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 @@ - -
-
-[Home]
-[Search]
-[D]
-- - Most of this specification remains TBD (To Be Defined). - -
- 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:
-
- - 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. - - -
- - 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 -
- - - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
++ + Most of this specification remains TBD (To Be Defined). + +
+ 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:
+
+ + 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. + + +
+ + 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 +
+
+ + + + 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 @@ - - - -
-
-[Home]
-[Search]
-[D]
-
-- 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 - -
- - - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
++ 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 + +
+
+ + + + 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 @@ - - - - - -
-[Home]
-[Search]
-[D]
-| int* p; | Pointers to data - - |
| int[3] s; | Static arrays - - |
| int[] a; | Dynamic arrays - - |
| int[char[]] x; | Associative arrays - |
- 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. - -
- 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. - -
- 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. - -
- 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 -- - -
- // 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. - -
- - 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 -- -
- 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. - -
- 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. - -
- 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 -- -
- - 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 -- - - -
- - 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 -- -
- 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
- }
-
-
-- 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]; -- -
- 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 -- -
| .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 -- -
- 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.
-
-
- 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. - -
- 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.
-
-
-- 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). - - - -
- - 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' -- -
- 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.
-
-- - 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);
- }
- }
-
-
-| .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. - - |
- 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;
- }
-
-
-
+
+Home
+| Search
+| D
+
+| int* p; | Pointers to data + + |
| int[3] s; | Static arrays + + |
| int[] a; | Dynamic arrays + + |
| int[char[]] x; | Associative arrays + |
+ + 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. + +
+ + 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. + +
+ + 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. + +
+ + 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 + |
+ + +
+ + // 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. + +
+ + 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. + +
+ + 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. + +
+ + 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 + |
+ +
+ + + 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 + |
+ + + +
+ + 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 + |
+ +
+
+ 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
+ }
+ |
+ +
+ + 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]; + |
+ +
+ + 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 + |
+ +
| .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. + +
+ + 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. + + +
+ + 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' + |
+ +
+
+ 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. + +
+ + 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);
+ }
+ }
+ |
+ +
| .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. + + |
+
+ 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;
+ }
+ |
+ +
+
+ + + + + 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 @@ - - - - - -
-[Home]
-[Search]
-[D]
-
- 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;
- ...
- }
-
-
-- 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 - ); -- -
- 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
- {
- void oldFoo();
- }
-
-
- Implementation Note: The compiler should have a switch
- specifying if deprecated declarations should be compiled with
- out complaint or not.
-
-
-- - 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 -- - The const attribute declares constants that can be - evaluated at compile time. For example: - -
- const int foo = 7;
-
- const
- {
- double bar = foo + 6;
- }
-
-
-- 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 -- - 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 -- - 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. - - -
- - 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.' - -
- - - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
+
+ + 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;
+ ...
+ }
+
+
+
+ + 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 + ); + |
+ +
+ + 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
+ {
+ void oldFoo();
+ }
+ |
+ + Implementation Note: The compiler should have a switch + specifying if deprecated declarations should be compiled with + out complaint or not. + + +
+ + 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 + |
+ + The const attribute declares constants that can be + evaluated at compile time. For example: + +
+
+ const int foo = 7;
+
+ const
+ {
+ double bar = foo + 6;
+ }
+ |
+ +
+ + 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 + |
+ + 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 + |
+ + 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. + + +
+ + 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.' + + +
+
+ + + + 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 @@ - - - - - -
-
-[Home]
-[Search]
-[D]
-
-- -
- -
- -
- -
---
-- replace uint buffer lengths with size_t -
- add line-by-line opApply to Stream and InputStream (due to Regan - Heath)
- int opApply(int delegate(inout char[] line) dg)
- int opApply(int delegate(inout ulong n, inout char[] line) dg)
- int opApply(int delegate(inout wchar[] line) dg)
- int opApply(int delegate(inout ulong n, inout wchar[] line) dg) -- move readable/writeable/seekable tests from contracts to the body - since phobos is compiled in release mode and users can easily try - to write to an unwritable stream -
- return "this" from writef and writefln to allow chaining (eg flush) -
- fix TArrayStream read/write to check for "eof" (Derick Eddington) -
- make SliceStream preserve the source buffer position if seekable - and pay attention to isOpen (Derick) -
- implement available() for more stream types (Derick) -
- copyFrom bug fixes and position preserving if seekable (Derick) -
- move the initialization of the BOMs to the initializer instead of the - module constructor. -
- make isopen protected (from private) so that subclasses can see it. -
- more unittest (Derick and Ben) -
- fix File.size() bug on Windows -
- fix File.open() error message to say "Cannot open or create file" -
- -
- -
- -
- -
- module foo.bar;- then bar is not in scope, one must use foo.bar. -
- -
- -
- IPv6 not supported but the C interface for it should all be there. - Split up socket.d and put the C stuff in std.c modules. - std.c.linux.linux updated because most of the socket functions - are actually regular I/O functions. Added classes Protocol and Service. - Added Socket.accepting() to allow derived classes to be - accepted. - Documentation and samples updated. - Fixed major bug in the linux version. -- -
- -
- -Note: This is a library only change, the dmd executables are still -at 0.111. - -
- I've attached modified versions of std.stream and mmfile and the help - section for std.mmfile and std.stream. - The std.mmfile changes are: ---
- The std.stream changes are: -- change module declaration to std.mmfile -
- change class declaration to not be auto -
- add mMode read-only property to get the file mode of type MmFile.Mode -
-
-- added Dave Fladebo's performance improvements for buffered readLine -
- fixed a bug in read/write cfloat/cdouble/creal endian support -
- uncommented MmFileStream and cleaned it up to use MmFile's mode property. -
- template foo(T:T[]) -- now correctly resolve T in foo(int[]) to int rather than int[]. -
- char[][] foo; - foo = new char[][45]; // new, correct way to allocate array of 45 strings - //foo = new char[45][]; // old, now wrong, way --
- int[3][4] a; // a is 4 arrays of 3 arrays of ints - int b[4][3]; // b is 4 arrays of 3 arrays of ints --
- byte b = 0x10; // ok - ubyte c = 0x100; // error - byte d = 0x80; // error - ubyte e = 0x80; // ok --
+
+Home
+| Search
+| D
+
++ +
+ +
+ +
+ +
+ +
+++
+- replace uint buffer lengths with size_t +
- add line-by-line opApply to Stream and InputStream (due to Regan + Heath)
+ int opApply(int delegate(inout char[] line) dg)
+ int opApply(int delegate(inout ulong n, inout char[] line) dg)
+ int opApply(int delegate(inout wchar[] line) dg)
+ int opApply(int delegate(inout ulong n, inout wchar[] line) dg) +- move readable/writeable/seekable tests from contracts to the body + since phobos is compiled in release mode and users can easily try + to write to an unwritable stream +
- return "this" from writef and writefln to allow chaining (eg flush) +
- fix TArrayStream read/write to check for "eof" (Derick Eddington) +
- make SliceStream preserve the source buffer position if seekable + and pay attention to isOpen (Derick) +
- implement available() for more stream types (Derick) +
- copyFrom bug fixes and position preserving if seekable (Derick) +
- move the initialization of the BOMs to the initializer instead of the + module constructor. +
- make isopen protected (from private) so that subclasses can see it. +
- more unittest (Derick and Ben) +
- fix File.size() bug on Windows +
- fix File.open() error message to say "Cannot open or create file" +
+ +
+ +
+ +
+ +
+ module foo.bar;+ then bar is not in scope, one must use foo.bar. +
+ +
+ +
+ IPv6 not supported but the C interface for it should all be there. + Split up socket.d and put the C stuff in std.c modules. + std.c.linux.linux updated because most of the socket functions + are actually regular I/O functions. Added classes Protocol and Service. + Added Socket.accepting() to allow derived classes to be + accepted. + Documentation and samples updated. + Fixed major bug in the linux version. ++ +
+ +
+ +Note: This is a library only change, the dmd executables are still +at 0.111. + +
+ I've attached modified versions of std.stream and mmfile and the help + section for std.mmfile and std.stream. + The std.mmfile changes are: +++
+ The std.stream changes are: +- change module declaration to std.mmfile +
- change class declaration to not be auto +
- add mMode read-only property to get the file mode of type MmFile.Mode +
+
+- added Dave Fladebo's performance improvements for buffered readLine +
- fixed a bug in read/write cfloat/cdouble/creal endian support +
- uncommented MmFileStream and cleaned it up to use MmFile's mode property. +
+ template foo(T:T[]) ++ now correctly resolve T in foo(int[]) to int rather than int[]. +
+ char[][] foo; + foo = new char[][45]; // new, correct way to allocate array of 45 strings + //foo = new char[45][]; // old, now wrong, way ++
+ int[3][4] a; // a is 4 arrays of 3 arrays of ints + int b[4][3]; // b is 4 arrays of 3 arrays of ints ++
+ byte b = 0x10; // ok + ubyte c = 0x100; // error + byte d = 0x80; // error + ubyte e = 0x80; // ok ++
+
+ + + + 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 @@ - - - - - -
-
-[Home]
-[Search]
-[D]
-
-- - 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:
-
-
- 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;
-
-
-- - 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. - -
- .offsetof Offset in bytes of field from beginning - of class -- -
- 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: -
- this() { this(1); }
- this(int i) { this(); } // illegal, cyclic constructor calls
-
-
- this() { a || super(); } // illegal
-
- this() { this(1) || super(); } // ok
-
- this()
- {
- for (...)
- {
- super(); // illegal, inside loop
- }
- }
-
- - A a = new A(3); -- - The following steps happen: - -
- 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. - -
- 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
- }
-
-- 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
- }
-
-- 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. - -
- 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);
- }
- }
-
-
-- 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. - -
- 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 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.
-
-
- 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
-
-
-- - 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: - -
+
+Home
+| Search
+| D
+
++ + 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:
+
+
+ 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;
+
+
++ + 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. + +
+ 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
+ }
+
+
++ 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: +
+ this() { this(1); }
+ this(int i) { this(); } // illegal, cyclic constructor calls
+
+
+ this() { a || super(); } // illegal
+
+ this() { this(1) || super(); } // ok
+
+ this()
+ {
+ for (...)
+ {
+ super(); // illegal, inside loop
+ }
+ }
+
+ + A a = new A(3); ++ + The following steps happen: + +
+ 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. + +
+ 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
+ }
+
++ 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
+ }
+
++ 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. + +
+ 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);
+ }
+ }
+
+
++ 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. + +
+ 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 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.
+
+
+ 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
+
+
++ + 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: + +
+
+ + + + 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 @@ - - -
-
-[Home]
-[Search]
-[D]
-
-- 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). - -
- 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. - -
- "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: - -
- - - 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.
-
-
-
- - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
+
+ + 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). + +
+ + 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. + +
+ "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: + +
+ + + 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.
+
+
+
+ + + + 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 @@ - - -
-
-[Home]
-[Search]
-[D]
-
-- - 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. - -
- - 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 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- - 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: - -- 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); - } -
- 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.
-
-
- 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;
- }
-
-
-
- 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:
-
-
- 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().
-
-- - 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. - -
-
- 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
-
- -
- - - - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
++ + 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. + +
+ + 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 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 |
+ + 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. + +
+
+ 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;
+ }
+ |
+ +
+
+ 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: + +
+
+ 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(). + +
+ + 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. + +
+
+ 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
+
+ +
+
+ + + + 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 @@ - - -
-
-[Home]
-[Search]
-[D]
-
-- - 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.) - -
- 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; -- -
- 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 -- -
- string str; - if (str.empty()) - // string is empty -- - In D, an empty string is just null: - -
- char[] str; - if (!str) - // string is empty -- - -
- 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; -- -
- 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. - -
- 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" -- -
- 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*. - -
- 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.
-
-- 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" -- -
- - 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. - -
- 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 - |
- #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;
- }
-
-
-
-- - - - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
++ + 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.) + +
+ + 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; + + |
+ +
+ + 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 + + |
+ +
+ + string str; + if (str.empty()) + // string is empty + |
+ + In D, an empty string is just null: + +
+ + char[] str; + if (!str) + // string is empty + |
+ + +
+ + 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; + |
+ +
+ + 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. + +
+ + 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" + |
+ +
+ + 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*. + +
+
+ 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. + +
+ + 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" + |
+ +
+ + 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. + +
+
+ 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 + |
+
+ #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;
+ }
+ |
+ +
+
+ + + + 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 @@ - - - - - -
-
-[Home]
-[Search]
-[D]
-
-- -See also: Programming in D for C Programmers - -
-
-
- class Foo
- {
- Foo(int x);
- };
-
-
-
- class Foo
- {
- this(int x) { }
- }
-
-
- which reflects how they are used in D.
-
-
- class A { A() {... } };
- class B : A
- {
- B(int x)
- : A() // call base constructor
- { ...
- }
- };
-
-
-
- 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;
- }
- }
-
-
-- 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++. - -
- A x, y; - ... - if (x == y) - ... -- -
- #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)
- ...
-
-
-- 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. - -
- 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; }
-
-
-
- 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.
-
-
- 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.
-
-
- 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 Foo
- {
- int x;
- }
- using Foo::x;
-
-
-- ---- 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. - -
- class File
- { Handle *h;
-
- ~File()
- {
- h->release();
- }
- };
-
-
-- - 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
- }
-
-
-
- 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.
-
-
- 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. - -
- 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
- }
-
-
-
- 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
- }
-
-
-
-- - - + + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
+
+
+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 + +
+
+ class Foo
+ {
+ Foo(int x);
+ }; |
+ +
+
+ class Foo
+ {
+ this(int x) { }
+ } |
+ + which reflects how they are used in D. + +
+
+ class A { A() {... } };
+ class B : A
+ {
+ B(int x)
+ : A() // call base constructor
+ { ...
+ }
+ }; |
+ +
+
+ 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;
+ }
+ } |
+ +
+ + 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++. + +
+ + A x, y; + ... + if (x == y) + ... + |
+ +
+ + #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)
+ ...
+ |
+ +
+ + 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. + +
+
+ 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; }
+ |
+ +
+
+ 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. + +
+
+ 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. + +
+
+ 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 Foo
+ {
+ int x;
+ }
+ using Foo::x;
+ |
+ +
+ + ---- 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. + +
+
+ class File
+ { Handle *h;
+
+ ~File()
+ {
+ h->release();
+ }
+ };
+ |
+ +
+ + 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
+ }
+ |
+ +
+
+ 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. + +
+
+ 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. + +
+
+ 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
+ } |
+ +
+
+ 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
+ } |
+ +
+
+ + + + 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 @@ - - - - -
-
-[Home]
-[Search]
-[D]
-
-
-
-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. - -
- sizeof(int) - sizeof(char *) - sizeof(double) - sizeof(struct Foo) -- -
Use the size property:
- -- int.size - (char *).size - double.size - Foo.size -- -
- #include <limits.h> - #include <math.h> - - CHAR_MAX - CHAR_MIN - ULONG_MAX - DBL_MIN -- -
- char.max - char.min - ulong.max - double.min -- -
- 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. - -
- #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 --
- 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 -- -
- #include <math.h> - - float f = fmodf(x,y); - double d = fmod(x,y); - long double e = fmodl(x,y); --
-D supports the remainder ('%') operator on floating point operands: -
- float f = x % y; - double d = x % y; - extended e = x % y; -- -
- 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); --
- D offers a full complement of comparisons and operators - that work with NAN arguments. -
- result = (x < y); // false if x or y is nan -- -
-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); --
-D simply builds assert into the language: -
- assert(e == 0); --
-[NOTE: trace functions?] - -
- #define ARRAY_LENGTH 17 - int array[ARRAY_LENGTH]; - for (i = 0; i < ARRAY_LENGTH; i++) - array[i] = value; --
- int array[17]; - array[] = value; -- -
- 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 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); -- - -
- #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;
-
-
-- int[] array; - - array.length = array.length + 1; - array[array.length - 1] = x; --
- 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));
-
-- char[] s1; - char[] s2; - char[] s; - - s = s1 ~ s2; - s ~= "hello"; --
- #include <stdio.h>
-
- printf("Calling all cars %d times!\n", ntimes);
-
-
- import stdio;
-
- printf("Calling all cars %d times!\n", ntimes);
-
-
- void forwardfunc();
-
- void myfunc()
- {
- forwardfunc();
- }
-
- void forwardfunc()
- {
- ...
- }
-
-
- void myfunc()
- {
- forwardfunc();
- }
-
- void forwardfunc()
- {
- ...
- }
-
-- void function(void); --
- void function()
- {
- ...
- }
-
-
- for (i = 0; i < 10; i++)
- {
- for (j = 0; j < 10; j++)
- {
- if (j == 3)
- goto Louter;
- if (j == 4)
- goto L2;
- }
- L2:
- ;
- }
- Louter:
- ;
-
-
- 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
-
-
- typedef struct ABC { ... } ABC;
-
-
- struct ABC { ... };
-
-
-
- #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.
-
-
- 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.
-
-
- #pragma pack(1)
- struct ABC
- {
- ...
- };
- #pragma pack()
-
- But #pragmas are nonportable both in theory and in practice from
- compiler to compiler.
-
-
- 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
- }
-
-
- 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.
-
-
- struct Foo
- { int i;
- union
- {
- struct { int x; long y; }
- char* p;
- }
- }
-
- Foo f;
-
- f.i;
- f.x;
- f.y;
- f.p;
-
-
-
- struct Foo { int x; int y; } foo;
-
- Or to separate the two:
-
- struct Foo { int x; int y; }; // note terminating ;
- struct Foo foo;
-
-
- 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.
-
-
- #include <stddef>
- struct Foo { int x; int y; };
-
- off = offsetof(Foo, y);
-
-
- struct Foo { int x; int y; }
-
- off = Foo.y.offset;
-
-
-
- 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.
-
-
- union U { int a; long b; }
- U x = { a:5 }
-
- avoiding the confusion and maintenance problems.
-
-
- 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.
-
-
- struct S { int a; int b; }
- S x = { b:3, a:5 }
-
- The meaning is clear, and there no longer is a 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 };
-
-- 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 -- -
- 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[] = "\"[^\\\\]*(\\\\.[^\\\\]*)*\""; --
- char[] file = 'c:\root\file.c'; - char[] quoteString = \" r"[^\\]*(\\.[^\\]*)*" \"; -- The famous hello world string becomes: -
- char[] hello = "hello world" \n; -- -
Modern programming requires that wchar strings be supported in an easy way, for internationalization of the programs. - -
- #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");
-
-- char[] foo_ascii = "hello"; // string is taken to be ascii - wchar[] foo_wchar = "hello"; // string is taken to be wchar -- -
- 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.
-
-
- enum COLORS { red, blue, green }
-
- char[][COLORS.max + 1] cstring =
- [
- COLORS.red : "red",
- COLORS.blue : "blue",
- COLORS.green : "green",
- ];
-
-
-Not perfect, but better.
-
-- 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.
-
-- 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. - -
- 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. - -
- A x, y; - ... - if (x == y) - ... -- - -
- 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. - -
- 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. - -
- 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.
-
-
-- type[] array; - ... - array.sort; // sort array in-place -- -
- volatile int *p = address; - - i = *p; -- -
- int* p = address;
-
- volatile { i = *p; }
-
-
-- "This text spans\n\ - multiple\n\ - lines\n" -- - If there is a lot of text, this can wind up being tedious. - -
- "This text spans - multiple - lines - " -- - So blocks of text can just be cut and pasted into the D - source. - -
- - 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 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;
- }
-
-
-- 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. - -
- myint i, j; - ... - j = i >>> 3; -- - avoids the unsafe cast and will work as expected with any integral - type. - -
- - 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.
-
--
- 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. - - -
- - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
+
+
+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. + +
+ sizeof(int) + sizeof(char *) + sizeof(double) + sizeof(struct Foo) |
+ +
Use the size property:
+ +
+ int.size + (char *).size + double.size + Foo.size |
+ +
+ #include <limits.h> + #include <math.h> + + CHAR_MAX + CHAR_MIN + ULONG_MAX + DBL_MIN + |
+ +
+ char.max + char.min + ulong.max + double.min + |
+ +
+ 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. + +
+ #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 + |
+ +
+ 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 + |
+ +
+ + #include <math.h> + + float f = fmodf(x,y); + double d = fmod(x,y); + long double e = fmodl(x,y); + |
+ +
+ + float f = x % y; + double d = x % y; + extended e = x % y; + |
+ +
+ + #include <math.h> + + if (isnan(x) || isnan(y)) + result = FALSE; + else + result = (x < y); + |
+ +
+ D offers a full complement of comparisons and operators + that work with NAN arguments. + +
+ result = (x < y); // false if x or y is nan + |
+ +
+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); + |
+ +
+ + assert(e == 0); + |
+ +[NOTE: trace functions?] + +
+ + #define ARRAY_LENGTH 17 + int array[ARRAY_LENGTH]; + for (i = 0; i < ARRAY_LENGTH; i++) + array[i] = value; + |
+ +
+ + int array[17]; + array[] = value; + |
+ +
+ 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]); + |
+ +
+ + 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); + |
+ + +
+
+ #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;
+ |
+ +
+ + int[] array; + + array.length = array.length + 1; + array[array.length - 1] = x; + |
+ +
+
+ #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));
+ |
+ +
+ + char[] s1; + char[] s2; + char[] s; + + s = s1 ~ s2; + s ~= "hello"; + |
+ +
+
+ #include <stdio.h>
+
+ printf("Calling all cars %d times!\n", ntimes);
+ |
+ +
+
+ import stdio;
+
+ printf("Calling all cars %d times!\n", ntimes);
+ |
+ +
+
+ void forwardfunc();
+
+ void myfunc()
+ {
+ forwardfunc();
+ }
+
+ void forwardfunc()
+ {
+ ...
+ }
+ |
+ +
+
+ void myfunc()
+ {
+ forwardfunc();
+ }
+
+ void forwardfunc()
+ {
+ ...
+ }
+ |
+ +
+ + void function(void); + |
+ +
+
+ void function()
+ {
+ ...
+ }
+ |
+ +
+
+ for (i = 0; i < 10; i++)
+ {
+ for (j = 0; j < 10; j++)
+ {
+ if (j == 3)
+ goto Louter;
+ if (j == 4)
+ goto L2;
+ }
+ L2:
+ ;
+ }
+ Louter:
+ ;
+ |
+ +
+
+ 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
+ |
+ +
+
+ typedef struct ABC { ... } ABC;
+ |
+ +
+
+ struct ABC { ... };
+ |
+ +
+
+ #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. + +
+
+ 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. + +
+
+ #pragma pack(1)
+ struct ABC
+ {
+ ...
+ };
+ #pragma pack()
+ |
+ + But #pragmas are nonportable both in theory and in practice from + compiler to compiler. + +
+
+ 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
+ }
+ |
+ +
+
+ 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. + +
+
+ struct Foo
+ { int i;
+ union
+ {
+ struct { int x; long y; }
+ char* p;
+ }
+ }
+
+ Foo f;
+
+ f.i;
+ f.x;
+ f.y;
+ f.p;
+ |
+ +
+
+ struct Foo { int x; int y; } foo;
+ |
+ + Or to separate the two: + +
+
+ struct Foo { int x; int y; }; // note terminating ;
+ struct Foo foo;
+ |
+ +
+
+ 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. + +
+
+ #include <stddef>
+ struct Foo { int x; int y; };
+
+ off = offsetof(Foo, y);
+ |
+ +
+
+ struct Foo { int x; int y; }
+
+ off = Foo.y.offset;
+ |
+ +
+
+ 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. + +
+
+ union U { int a; long b; }
+ U x = { a:5 }
+ |
+ + avoiding the confusion and maintenance problems. + +
+
+ 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. + +
+
+ struct S { int a; int b; }
+ S x = { b:3, a:5 }
+ |
+ + The meaning is clear, and there no longer is a 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 };
+ |
+
+ + 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 + |
+ +
+ + 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[] = "\"[^\\\\]*(\\\\.[^\\\\]*)*\""; + |
+
+ + char[] file = 'c:\root\file.c'; + char[] quoteString = \" r"[^\\]*(\\.[^\\]*)*" \"; + |
+ The famous hello world string becomes: +
+ + char[] hello = "hello world" \n; + |
+ +
Modern programming requires that wchar strings be supported in an easy way, for internationalization of the programs. + +
+ + #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");
+ |
+
+ + char[] foo_ascii = "hello"; // string is taken to be ascii + wchar[] foo_wchar = "hello"; // string is taken to be wchar + |
+ +
+
+ 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. + +
+
+ enum COLORS { red, blue, green }
+
+ char[][COLORS.max + 1] cstring =
+ [
+ COLORS.red : "red",
+ COLORS.blue : "blue",
+ COLORS.green : "green",
+ ];
+ |
+ +Not perfect, but better. + +
+ + 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. + +
+ + 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. + +
+ + 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. + +
+ + A x, y; + ... + if (x == y) + ... + |
+ + +
+ + 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. + +
+ + 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. + +
+
+ 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. + + +
+ + type[] array; + ... + array.sort; // sort array in-place + |
+ +
+ + volatile int *p = address; + + i = *p; + |
+ +
+
+ int* p = address;
+
+ volatile { i = *p; }
+ |
+ +
+ + "This text spans\n + multiple\n + lines\n" + |
+ + If there is a lot of text, this can wind up being tedious. + +
+ + "This text spans + multiple + lines + " + |
+ + So blocks of text can just be cut and pasted into the D + source. + +
+ + 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 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;
+ }
+ |
+ +
+ + 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. + +
+ + myint i, j; + ... + j = i >>> 3; + |
+ + avoids the unsafe cast and will work as expected with any integral + type. + +
+ + 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. + +
+ 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. + +
+
+ + + + 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 @@ - - -
-[Home]
-[Search]
-[D]
-- - Building contract support into the language makes for: - -
-
- 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(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.
-
-
- 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.
-
-- Conversely, all of the out contracts needs to be satisified, so - overriding functions becomes a processes of tightening the out - contracts. - - - -
- - - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
++ + Building contract support into the language makes for: + +
+
+ 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(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.
+
+
+
+ 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. + +
+ Conversely, all of the out contracts needs to be satisified, so + overriding functions becomes a processes of tightening the out + contracts. + + + +
+
+ + + + 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 @@ - - - -
-[Home]
-[Search]
-[D]
-- - A typical session might look like: - -
- C:\Documents and Settings\Your Name>cd \ - C:\>unzip dmd.zip - C:\>unzip dmc.zip -- -
- \dmd\bin\shell all.sh -- in the \dmd\samples\d directory for several small examples. - -
-
| 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 - |
- - 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 -- -
- set LIB=\dmd\lib;\dm\lib- -
- set LINKCMD=\dm\bin\link- -
- - 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" -- -
- cp dmd/bin/dmd.conf /etc -- -
- chmod u+x dmd/bin/dmd dmd/bin/obj2asm dmd/bin/dumpobj -- -
- cp dmd/lib/libphobos.a /usr/lib -- -
-
| Extension - | File Type - |
|---|---|
| none - | D source files - |
| .d - | D source files - |
| .o - | Object files to link in - |
| .a - | Library files to link in - |
- - The actual linking is done by running gcc. - This ensures compatibility with modules compiled with gcc. - -
- - 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" -- -
- - - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
++ + A typical session might look like: + +
+ C:\Documents and Settings\Your Name>cd + C:\>unzip dmd.zip + C:\>unzip dmc.zip ++ +
+ \dmd\bin\shell all.sh ++ in the \dmd\samples\d directory for several small examples. + +
+
| 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 + |
+ + 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 ++ +
+ set LIB=\dmd\lib;\dm\lib+ +
+ set LINKCMD=\dm\bin\link+ +
+ + 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" ++ +
+ cp dmd/bin/dmd.conf /etc ++ +
+ chmod u+x dmd/bin/dmd dmd/bin/obj2asm dmd/bin/dumpobj ++ +
+ cp dmd/lib/libphobos.a /usr/lib ++ +
+
| Extension + | File Type + |
|---|---|
| none + | D source files + |
| .d + | D source files + |
| .o + | Object files to link in + |
| .a + | Library files to link in + |
+ + The actual linking is done by running gcc. + This ensures compatibility with modules compiled with gcc. + +
+ + 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" ++ +
+
+ + + + 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 @@ - - - - - -
-[Home]
-[Search]
-[D]
-- 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 - -- -
- 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 -- -
- 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 -- - -
- 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.
-
-
- 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. - -
- 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.
-
-- - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
+
+ + 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 + + |
+ +
+ + 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. + +
+
+ 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. + +
+
+ + + + 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 @@ - - - - - - - - - - - - -
-
-[Home]
-[Search]
-[D]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Corto's
- D button images:
-
-
-
-
- If you'd like to contribute more images, please - email - them to Digital Mars! - -
-
-
-
+
+Home
+| Search
+| D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Corto's
+ D button images:
+
+
+
+ +
+
+ + + + + + + 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 @@ - - - - - -
-
-[Home]
-[Search]
-[D]
-
-- - 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. - -
- -
- 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:
- - 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: - -
-module mydll;
-export void dllprint() { printf("hello dll world\n"); }
-
-
- -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: - -
-import mydll;
-
-int main()
-{
- mydll.dllprint();
- return 0;
-}
-
-
- Create a clone of mydll2.d that doesn't have the function bodies:
-
- -export void dllprint(); -- - Compile and link with the command: -
-dmd test.d mydll.lib -- - and run: -
-C:>test -hello dll world -C:> -- - - -
- - There are many approaches to solving this problem: - -
- - 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.
-
-- - 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();
-}
-
-
- - -
- -
- -
- -
- -
- -
- -
- 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. -
- -
- -
-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...- - -
+
+Home
+| Search
+| D
+
++ + 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. + +
+ +
+
+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: +
+ 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: + +
+
+module mydll;
+export void dllprint() { printf("hello dll world\n"); }
+ |
+ +
+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: + +
+
+import mydll;
+
+int main()
+{
+ mydll.dllprint();
+ return 0;
+}
+ |
+ + Create a clone of mydll2.d that doesn't have the function bodies: + +
+ +export void dllprint(); + |
+ + Compile and link with the command: +
+dmd test.d mydll.lib ++ + and run: +
+C:>test +hello dll world +C:> ++ + + +
+ + There are many approaches to solving this problem: + +
+ + 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();
+}
+ |
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ 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. +
+ +
+ +
+
+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...+ +
+
+ + + + 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 @@ - - - - - -
-[Home]
-[Search]
-[D]
-Last update May 25, 2002 -
- statement; // comment - statement; // comment -- -
- /* - * comment - * comment - */ - statement; - statement; -- -
- /+++++ - /* - * comment - * comment - */ - statement; - statement; - +++++/ -- -
- int myFunc(); -- -
- -
- import std.c.stdio; -- Module names should be all lower case. -
- -
- class Foo; - class FooAndBar; -- -
- int done(); - int doneProcessing(); -- -
- alias void VOID; - alias int INT; - alias int* pint; -- - should be avoided. - -
- 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** -- -
+
+Home
+| Search
+| D
+
+
+ + statement; // comment + statement; // comment + |
+ +
+ + /* + * comment + * comment + */ + statement; + statement; + |
+ +
+ + /+++++ + /* + * comment + * comment + */ + statement; + statement; + +++++/ + |
+ +
+ + int myFunc(); + |
+ +
+ +
+ + import std.c.stdio; + |
+ Module names should be all lower case. +
+ +
+ + class Foo; + class FooAndBar; + |
+ +
+ + int done(); + int doneProcessing(); + |
+ +
+ + alias void VOID; + alias int INT; + alias int* pint; + |
+ + should be avoided. + +
+ + 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** + |
+ +
+
+ + + + 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 @@ - - -
-
-[Home]
-[Search]
-[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 | ♦ - - |
- - - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| 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 | ♦ + + |
+ + + + + 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 @@ - - - - -
-
-[Home]
-[Search]
-[D]
-
- 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.
-
-- .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 -- -
- enum X { A=3, B, C }
- X x; // x is initialized to 3
-
-
-- - - - + + + + + + + + + + + + + + + + + + + +
+ +
+
+Home
+| Search
+| D
+
+
+ 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.
+
++ .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 ++ +
+ enum X { A=3, B, C }
+ X x; // x is initialized to 3
+
+
++
+ + + + 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 @@ - - - - - -
-[Home]
-[Search]
-[D]
-- -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: - -
- -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? - -
+
+Home
+| Search
+| D
+
++ +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: + +
+ +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? + +
+
+ + + + 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 @@ - - - - - -
-[Home]
-[Search]
-[D]
-
-- - 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 -- -
- 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. - -
- 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. - - -
- 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. - -
- 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. - -
- 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. - -
- 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. - - -
- 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. - - -
- OrExpression | XorExpression -- - The operands are OR'd together. - -
- XorExpression ^ AndExpression -- - The operands are XOR'd together. - -
- AndExpression & EqualExpression -- - The operands are AND'd together. - - -
- 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. - - -
- 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. - -
- 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. - - -
- -
| Operator | Relation | -
|---|---|
| < | 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. - -
- - 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: -
- -
| 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 - - |
- 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.
-
-- 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 -- -
- 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. - -
- 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. - -
- & UnaryExpression - ++ UnaryExpression - -- UnaryExpression - * UnaryExpression - - UnaryExpression - + UnaryExpression - ! UnaryExpression - ~ UnaryExpression - delete UnaryExpression - NewExpression - cast ( Type ) UnaryExpression - ( Type ) . Identifier - ( Expression ) -- - -
- - 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. - -
- - The pointer or reference is set to null after the delete - is performed. - -
- (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
- }
-
-
-- PostfixExpression . Identifier - PostfixExpression -> Identifier - PostfixExpression ++ - PostfixExpression -- - PostfixExpression ( ArgumentList ) - PostfixExpression [ ArgumentList ] - PostfixExpression [ AssignExpression .. AssignExpression ] -- -
- 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. - - -
- 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. - -
- Identifier - .Identifier - this - super - null - true - false - NumericLiteral - CharacterLiteral - StringLiteral - FunctionLiteral - AssertExpression - BasicType . Identifier - typeid ( Type ) -- -
- 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'
- }
-
-
-
-- 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.
-
-
-- 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. - -
- TypeidExpression: - typeid ( Type ) -- - Returns an instance of class TypeInfo corresponding - to Type. - -
+
+Home
+| Search
+| D
+
++ + 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 + |
+ +
+ + 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. + +
+ + 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. + + +
+ + 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. + +
+ + 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. + +
+ + 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. + +
+ + 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. + + +
+ + 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. + + +
+ + OrExpression | XorExpression + |
+ + The operands are OR'd together. + +
+ + XorExpression ^ AndExpression + |
+ + The operands are XOR'd together. + +
+ + AndExpression & EqualExpression + |
+ + The operands are AND'd together. + + +
+ + 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. + + +
+ + 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. + +
+ + 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. + + +
+ +
| Operator | Relation | +
|---|---|
| < | 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. + +
+ + 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: +
+ +
| 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 + + |
+ + 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. + +
+ + 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 + |
+ +
+ + 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. + +
+ + 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. + +
+ + & UnaryExpression + ++ UnaryExpression + -- UnaryExpression + * UnaryExpression + - UnaryExpression + + UnaryExpression + ! UnaryExpression + ~ UnaryExpression + delete UnaryExpression + NewExpression + cast ( Type ) UnaryExpression + ( Type ) . Identifier + ( Expression ) + |
+ + +
+ + 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. + +
+ + The pointer or reference is set to null after the delete + is performed. + +
+ (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
+ }
+ |
+ +
+ + PostfixExpression . Identifier + PostfixExpression -> Identifier + PostfixExpression ++ + PostfixExpression -- + PostfixExpression ( ArgumentList ) + PostfixExpression [ ArgumentList ] + PostfixExpression [ AssignExpression .. AssignExpression ] + |
+ +
+ + 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. + + +
+ + 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. + +
+ + Identifier + .Identifier + this + super + null + true + false + NumericLiteral + CharacterLiteral + StringLiteral + FunctionLiteral + AssertExpression + BasicType . Identifier + typeid ( Type ) + |
+ +
+
+ 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'
+ }
+ |
+ + +
+ + 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. + + +
+ + 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. + +
+ + TypeidExpression: + typeid ( Type ) + |
+ + Returns an instance of class TypeInfo corresponding + to Type. + +
+
+ + + + 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 @@ - - - - - -
-
-[Home]
-[Search]
-[D]
-
-- -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. - - - -
- -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. - - - -
- -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. - -
- - 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. - -
- - 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. - -
- - 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. - -
- - 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. - -
-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);
-}
-
-
-
- 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.
-
-- 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. - -
- - 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 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. - - - - -
+
+Home
+| Search
+| D
+
++ +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. + + + +
+ +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. + + + +
+ +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. + +
+ + 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. + +
+ + 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. + +
+ + 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. + +
+ + 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. + +
+
+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);
+}
+ |
+ +
+
+ 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. + +
+ + 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. + +
+ + 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 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. + + + + +
+
+ + + + 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 @@ - - - - - -
-[Home]
-[Search]
-[D]
-
-- - 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: -
-
- 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
-
- 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:
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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:
+
+
+ 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
+
+ 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:
+
+
+
+ There is no particular complex literal syntax, just add a real and imaginary type:
+
+
+
+ Complex numbers have two properties:
+
+
+
-
- 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:
-
-
-
- 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.
-
-
-
- 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:
-
-
-
- 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:
-
-
-
- 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.
-
-
-
- Unlike module level declarations, declarations within function
- scope are processed in order. This means that two nested functions
- cannot mutually call each other:
-
-
-
- Future directions: Function pointers and delegates may merge
- into a common syntax and be interchangeable with each other.
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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:
+
+
+
+ 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:
+
+
+
+
+
+ However, when doing overload resolution, the functions in the base
+ class are not considered:
+
+
+
+ To consider the base class's functions in the overload resolution
+ process, use an AliasDeclaration:
+
+
+
+ A function parameter's default value is not inherited:
+
+
+
+
+
+
+ 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.
+
+
+
+ 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:
+
+
+
+
+
+
+ Variadic functions with non-D linkage must have at least one
+ non-variadic parameter declared.
+
+
+
+ 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:
+
+
+
+ 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.
+
+
+
+ which prints:
+
+
+
+ To protect against the vagaries of stack layouts on different
+ CPU architectures, use std.stdarg to access the variadic
+ arguments:
+
+
+
+
+
+ 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:
+
+
+
+ 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 can only be accessed by the most nested lexically
+ enclosing function, or by another nested function at the same
+ nesting depth:
+
+
+
+ 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.
+
+
+
+ This access can span multiple nesting levels:
+
+
+
+ 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.
+
+
+
+ Functions can be nested within member functions:
+
+
+
+ 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:
+
+
+
+ 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:
+
+
+
+ The solution is to use a delegate:
+
+
+
+ Future directions: This restriction may be removed.
+
+
+
+
+ A delegate can be set to a non-static nested function:
+
+
+
+ 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:
+
+
+
+ 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:
+
+
+
+ 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.
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- 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:
-
-
-
- To avoid this from happening,
-
-
-
- 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:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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.
-
-
-
-
+
+ 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:
+
+
+
+ To avoid this from happening,
+
+
+
+ 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:
+
+
+
+
+
+ The garbage collector does not scan non-pointer types for roots.
+
+
+
+
+
+ A compacting garbage collector may change this value.
+
+
+
+
+
+
+
+
+
+ since, again, the garbage collector can move objects around in
+ memory.
+
+
+
+
+
+ Misaligned pointers may be used if the underlying hardware
+ supports them and the pointer is never used to point
+ into the gc heap.
+
+
+
+ Using such a union, however, as a substitute for a cast(int) will
+ result in undefined behavior.
+
+
+
+
+
+
+ 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.
+
+
+
- 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.
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
-
- Remove all the #if, #ifdef, #include,
- etc. statements.
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Remove all the #if, #ifdef, #include,
+ etc. statements.
+
+
+
+ to give it C linkage.
+
+
+
+ with:
+
+
+
+
+
+ can be replaced with:
+
+
+
+ or with:
+
+
+
+ Function style macros, such as:
+
+
+
+ can be replaced with functions:
+
+
+
+
+
+ should be written as:
+
+
+
+
+
+ are in D:
+
+
+
+
+
+ becomes:
+
+
+
+
+
+ It can be replaced with two D modules, foo.d:
+
+
+
+ and fooextern.d:
+
+
+
+ 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.
+
+
+
+ becomes:
+
+
+
+
+
+ with:
+
+
+
+
+
+ becomes:
+
+
+
+
+
+ becomes:
+
+
+
+
+
+ becomes:
+
+
+
+
+
+ becomes:
+
+
+
+
+
+ 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.
+
+
+
-
- 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.
-
-
-
- Aligning the start of a loop body can sometimes have a dramatic
- effect on the execution speed.
-
-
-
- The following registers are supported. Register names
- are always in upper case.
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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.
+
+
+
+ Aligning the start of a loop body can sometimes have a dramatic
+ effect on the execution speed.
+
+
+
+ The following registers are supported. Register names
+ are always in upper case.
+
+
+
+
+ Last update Feb 10, 2005
-
-
- This is done by matching the C compiler's data types, layouts,
- and function call/return sequences.
-
-
-
- The C function must be declared and given a calling convention,
- most likely the "C" calling convention, for example:
-
-
-
- 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:
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- An improved D function for formatted output is
- std.stdio.writef().
-
-
-
- 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.
-
-
-
- D class objects are incompatible with C++ class objects.
-
-
+
+ This is done by matching the C compiler's data types, layouts,
+ and function call/return sequences.
+
+
+
+ The C function must be declared and given a calling convention,
+ most likely the "C" calling convention, for example:
+
+
+
+ and then it can be called within D code in the obvious way:
+
+
+
+ There are several things going on here:
+
+
+
+
+
+ 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:
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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().
+
+
+
+ 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.
+
+
+
+ D class objects are incompatible with C++ class objects.
+
+
+
-
-
-
-
-
-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:
-
-
-
- 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
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+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:
+
+
+
+ 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
+
+
+
-
-
-
- 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
-
-
- 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" ":
-
-
- 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
+
+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.
+
+
+
+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.
+
+
+
+ ireal j = 1.3i;
+
+
+
+ cdouble cd = 3.6 + 4i;
+ creal c = 4.5 + 2i;
+
+ .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
-
-[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.
-
- 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.
- 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 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.
-
- 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.
- 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.
-
- 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.
- 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
+
+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.
+
+
+
+ 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);
+ }
+
+
+
+ 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)
+ }
+
+
+
+ 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
+ }
+
+
+
+ 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)
+ }
+
+
+
+ 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.
+ 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);
+
+
+
+ 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
+
+
+
+ int abc(...); // ok, D linkage
+ extern (C) def(...); // error, must have at least one parameter
+
+
+
+ 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
+ }
+
+
+
+ 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);
+ }
+
+
+
+ 00870FD0
+ 4 arguments
+ int
+ 2
+ long
+ 3
+ double
+ 4.5
+ FOO
+ 00870FD0
+
+
+
+ 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.
+
+
+
+ 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
+ }
+ }
+ 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
+ }
+
+
+
+ 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
+ }
+
+
+
+ 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
+ }
+
+
+
+ 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);
+ }
+
+
+
+ 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);
+ }
+
+
+
+ struct Foo
+ { int a;
+
+ int bar()
+ { int c;
+
+ int foo()
+ {
+ return c + a;
+ }
+ }
+ }
+
+
+
+ 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()
+ }
+ }
+ }
+ }
+
+
+
+ void test()
+ {
+ void foo() { bar(); } // error, bar not defined
+ void bar() { foo(); } // ok
+ }
+
+
+
+ void test()
+ {
+ void delegate() fp;
+ void foo() { fp(); }
+ void bar() { foo(); }
+ fp = &bar;
+ }
+ 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
+ }
+
+
+
+ int delegate() dg;
+
+ void test()
+ { int a = 7;
+ int foo() { return a + 3; }
+
+ dg = &foo;
+ int i = dg(); // i is set to 10
+ }
+
+
+
+ int* bar()
+ { int b;
+ test();
+ int i = dg(); // error, test.a no longer exists
+ return &b; // error, bar.b not valid after bar() exits
+ }
+
+
+
+ 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
+ }
+ 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
-[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:
-
-
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright (c) 2004 by Digital Mars, All Rights Reserved
+
+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:
+
+
+
+
+Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-[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.
-
-
-
-
- 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.
-
-
-
-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.
-
-
-
-
- Things that are reliable and can be done:
-
-
- void* p;
- ...
- int x = cast(int)p; // error: undefined behavior
-
- The garbage collector does not scan non-pointer types for roots.
-
- p = cast(void*)(cast(int)p | 1); // error: undefined behavior
-
-
-
- p = cast(void*)12345678; // error: undefined behavior
-
- A compacting garbage collector may change this value.
-
- if (p1 < p2) // error: undefined behavior
- ...
- since, again, the garbage collector can move objects around in
- memory.
-
- char* p = new char[10];
- char* q = p + 6; // ok
- q = p + 11; // error: undefined behavior
- q = p - 1; // error: undefined behavior
-
-
-
- align (1) struct Foo
- { byte b;
- char* p; // misaligned pointer
- }
- Misaligned pointers may be used if the underlying hardware
- supports them and the pointer is never used to point
- into the gc heap.
-
-
-
-
- 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.
-
-
- union U { void* ptr; int value }
-
- Using such a union, however, as a substitute for a cast(int) will
- result in undefined behavior.
-
- char[] p = new char[10];
- char[] q = p[3..6];
- // q is enough to hold on to the object, don't need to keep
- // p as well.
-
-
- 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.
- References
-
-
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
+
+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.
+
+
+
+
+ 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.
+
+
+
+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.
+
+
+
+
+ Things that are reliable and can be done:
+
+
+
+
+ void* p;
+ ...
+ int x = cast(int)p; // error: undefined behavior
+
+
+
+ p = cast(void*)(cast(int)p | 1); // error: undefined behavior
+
+
+
+ p = cast(void*)12345678; // error: undefined behavior
+
+
+
+ if (p1 < p2) // error: undefined behavior
+ ...
+
+
+ char* p = new char[10];
+ char* q = p + 6; // ok
+ q = p + 11; // error: undefined behavior
+ q = p - 1; // error: undefined behavior
+
+
+
+ align (1) struct Foo
+ { byte b;
+ char* p; // misaligned pointer
+ }
+
+
+
+ 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.
+
+
+
+
+ union U { void* ptr; int value }
+
+
+
+ char[] p = new char[10];
+ char[] q = p[3..6];
+ // q is enough to hold on to the object, don't need to keep
+ // p as well.
+
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.
+ References
+
+
+
+
+Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-[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.
-
-
-
-
-
- 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
+
+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.
+
+
+
+
+ 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
-
-[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.
- 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
+
+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.
+ Linkage
+
+ Generally, surround the entire module with:
+
+
+
+
+ extern (C)
+ {
+ ...file contents...
+ }
+ 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"
+
+
+
+ cast(wchar[])"string"
+
Macros
+
+ Lists of macros like:
+
+
+
+
+ #define FOO 1
+ #define BAR 2
+ #define ABC 3
+ #define DEF 40
+
+
+
+ enum
+ { FOO = 1,
+ BAR = 2,
+ ABC = 3,
+ DEF = 40
+ }
+
+
+
+ const int FOO = 1;
+ const int BAR = 2;
+ const int ABC = 3;
+ const int DEF = 40;
+
+
+
+ #define MAX(a,b) ((a) < (b) ? (b) : (a))
+
+
+
+ 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;
+
+
+
+ int* p, s;
+ int q;
+ int[3] t;
+
Void Parameter Lists
+
+ Functions that take no parameters:
+
+
+
+
+ int foo(void);
+
+
+
+ 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);
+
+
+
+ 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;
+
+
+
+ struct Foo { }
+ import fooextern;
+
+
+
+ Foo bar;
+
Typedef
+
+ alias is the D equivalent to the C typedef:
+
+
+
+
+ typedef int foo;
+
+
+
+ alias int foo;
+
Structs
+
+ Replace declarations like:
+
+
+
+
+ typedef struct Foo
+ { int a;
+ int b;
+ } Foo, *pFoo, *lpFoo;
+
+
+
+ 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()
+
+
+
+ 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;
+ };
+
+
+
+ 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);
+
+
+
+ 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);
+
+
+
+ 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);
+ }
+ Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-
-[Home]
-[Search]
-[D]
-
-
Last update Apr 2, 2005
-
-
-D x86 Inline Assembler
-
-
-
-
-
- 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.
-
- 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.
- 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.
-
-
-
-
Special Cases
-
-
-
-
-
-
- asm
- {
- rep ;
- movsb ;
- }
-
-
-
- {
- rep ;
- nop ;
- }
-
- which produces the same result.
-
-
- 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
-
-
-
-
-
-
- jmp $ ;
-
- branches to the instruction following the jmp instruction.
- Opcodes Supported
-
-
-
-
-
- aaa
- aad
- aam
- aas
- adc
-
- add
- addpd
- addps
- addsd
- addss
-
- and
- andnpd
- andnps
- andpd
- andps
-
- arpl
- bound
- bsf
- bsr
- bswap
-
- bt
- btc
- btr
- bts
- call
-
- cbw
- cdq
- clc
- cld
- clflush
-
- cli
- clts
- cmc
- cmova
- cmovae
-
- cmovb
- cmovbe
- cmovc
- cmove
- cmovg
-
- cmovge
- cmovl
- cmovle
- cmovna
- cmovnae
-
- cmovnb
- cmovnbe
- cmovnc
- cmovne
- cmovng
-
- cmovnge
- cmovnl
- cmovnle
- cmovno
- cmovnp
-
- cmovns
- cmovnz
- cmovo
- cmovp
- cmovpe
-
- cmovpo
- cmovs
- cmovz
- cmp
- cmppd
-
- cmpps
- cmps
- cmpsb
- cmpsd
- cmpss
-
- cmpsw
- cmpxch8b
- cmpxchg
- comisd
- comiss
-
- cpuid
- cvtdq2pd
- cvtdq2ps
- cvtpd2dq
- cvtpd2pi
-
- cvtpd2ps
- cvtpi2pd
- cvtpi2ps
- cvtps2dq
- cvtps2pd
-
- cvtps2pi
- cvtsd2si
- cvtsd2ss
- cvtsi2sd
- cvtsi2ss
-
- cvtss2sd
- cvtss2si
- cvttpd2dq
- cvttpd2pi
- cvttps2dq
-
- cvttps2pi
- cvttsd2si
- cvttss2si
- cwd
- cwde
-
- da
- daa
- das
- db
- dd
-
- de
- dec
- df
- di
- div
-
- divpd
- divps
- divsd
- divss
- dl
-
- dq
- ds
- dt
- dw
- emms
-
- enter
- f2xm1
- fabs
- fadd
- faddp
-
- fbld
- fbstp
- fchs
- fclex
- fcmovb
-
- fcmovbe
- fcmove
- fcmovnb
- fcmovnbe
- fcmovne
-
- fcmovnu
- fcmovu
- fcom
- fcomi
- fcomip
-
- fcomp
- fcompp
- fcos
- fdecstp
- fdisi
-
- fdiv
- fdivp
- fdivr
- fdivrp
- feni
-
- ffree
- fiadd
- ficom
- ficomp
- fidiv
-
- fidivr
- fild
- fimul
- fincstp
- finit
-
- fist
- fistp
- fisub
- fisubr
- fld
-
- fld1
- fldcw
- fldenv
- fldl2e
- fldl2t
-
- fldlg2
- fldln2
- fldpi
- fldz
- fmul
-
- fmulp
- fnclex
- fndisi
- fneni
- fninit
-
- fnop
- fnsave
- fnstcw
- fnstenv
- fnstsw
-
- fpatan
- fprem
- fprem1
- fptan
- frndint
-
- frstor
- fsave
- fscale
- fsetpm
- fsin
-
- fsincos
- fsqrt
- fst
- fstcw
- fstenv
-
- fstp
- fstsw
- fsub
- fsubp
- fsubr
-
- fsubrp
- ftst
- fucom
- fucomi
- fucomip
-
- fucomp
- fucompp
- fwait
- fxam
- fxch
-
- fxrstor
- fxsave
- fxtract
- fyl2x
- fyl2xp1
-
- hlt
- idiv
- imul
- in
- inc
-
- ins
- insb
- insd
- insw
- int
-
- into
- invd
- invlpg
- iret
- iretd
-
- ja
- jae
- jb
- jbe
- jc
-
- jcxz
- je
- jecxz
- jg
- jge
-
- jl
- jle
- jmp
- jna
- jnae
-
- jnb
- jnbe
- jnc
- jne
- jng
-
- jnge
- jnl
- jnle
- jno
- jnp
-
- jns
- jnz
- jo
- jp
- jpe
-
- jpo
- js
- jz
- lahf
- lar
-
- ldmxcsr
- lds
- lea
- leave
- les
-
- lfence
- lfs
- lgdt
- lgs
- lidt
-
- lldt
- lmsw
- lock
- lods
- lodsb
-
- lodsd
- lodsw
- loop
- loope
- loopne
-
- loopnz
- loopz
- lsl
- lss
- ltr
-
- maskmovdqu
- maskmovq
- maxpd
- maxps
- maxsd
-
- maxss
- mfence
- minpd
- minps
- minsd
-
- minss
- mov
- movapd
- movaps
- movd
-
- movdq2q
- movdqa
- movdqu
- movhlps
- movhpd
-
- movhps
- movlhps
- movlpd
- movlps
- movmskpd
-
- movmskps
- movntdq
- movnti
- movntpd
- movntps
-
- movntq
- movq
- movq2dq
- movs
- movsb
-
- movsd
- movss
- movsw
- movsx
- movupd
-
- movups
- movzx
- mul
- mulpd
- mulps
-
- mulsd
- mulss
- neg
- nop
- not
-
- or
- orpd
- orps
- out
- outs
-
- outsb
- outsd
- outsw
- packssdw
- packsswb
-
- packuswb
- paddb
- paddd
- paddq
- paddsb
-
- paddsw
- paddusb
- paddusw
- paddw
- pand
-
- pandn
- pavgb
- pavgw
- pcmpeqb
- pcmpeqd
-
- pcmpeqw
- pcmpgtb
- pcmpgtd
- pcmpgtw
- pextrw
-
- pinsrw
- pmaddwd
- pmaxsw
- pmaxub
- pminsw
-
- pminub
- pmovmskb
- pmulhuw
- pmulhw
- pmullw
-
- pmuludq
- pop
- popa
- popad
- popf
-
- popfd
- por
- prefetchnta
- prefetcht0
- prefetcht1
-
- prefetcht2
- psadbw
- pshufd
- pshufhw
- pshuflw
-
- pshufw
- pslld
- pslldq
- psllq
- psllw
-
- psrad
- psraw
- psrld
- psrldq
- psrlq
-
- psrlw
- psubb
- psubd
- psubq
- psubsb
-
- psubsw
- psubusb
- psubusw
- psubw
- punpckhbw
-
- punpckhdq
- punpckhqdq
- punpckhwd
- punpcklbw
- punpckldq
-
- punpcklqdq
- punpcklwd
- push
- pusha
- pushad
-
- pushf
- pushfd
- pxor
- rcl
- rcpps
-
- rcpss
- rcr
- rdmsr
- rdpmc
- rdtsc
-
- rep
- repe
- repne
- repnz
- repz
-
- ret
- retf
- rol
- ror
- rsm
-
- rsqrtps
- rsqrtss
- sahf
- sal
- sar
-
- sbb
- scas
- scasb
- scasd
- scasw
-
- seta
- setae
- setb
- setbe
- setc
-
- sete
- setg
- setge
- setl
- setle
-
- setna
- setnae
- setnb
- setnbe
- setnc
-
- setne
- setng
- setnge
- setnl
- setnle
-
- setno
- setnp
- setns
- setnz
- seto
-
- setp
- setpe
- setpo
- sets
- setz
-
- sfence
- sgdt
- shl
- shld
- shr
-
- shrd
- shufpd
- shufps
- sidt
- sldt
-
- smsw
- sqrtpd
- sqrtps
- sqrtsd
- sqrtss
-
- stc
- std
- sti
- stmxcsr
- stos
-
- stosb
- stosd
- stosw
- str
- sub
-
- subpd
- subps
- subsd
- subss
- sysenter
-
- sysexit
- test
- ucomisd
- ucomiss
- ud2
-
- unpckhpd
- unpckhps
- unpcklpd
- unpcklps
- verr
-
- verw
- wait
- wbinvd
- wrmsr
- xadd
-
- xchg
- xlat
- xlatb
- xor
- xorpd
-
-
- xorps
-
-
-
-
- Pentium 4 (Prescott) Opcodes Supported
-
-
-
-
-
- addsubpd
- addsubps
- fisttp
- haddpd
- haddps
-
- hsubpd
- hsubps
- lddqu
- monitor
- movddup
-
-
- movshdup
- movsldup
- mwait
-
-
-
- AMD Opcodes Supported
-
-
-
-
-
- pavgusb
- pf2id
- pfacc
- pfadd
- pfcmpeq
-
- pfcmpge
- pfcmpgt
- pfmax
- pfmin
- pfmul
-
- pfnacc
- pfpnacc
- pfrcp
- pfrcpit1
- pfrcpit2
-
- pfrsqit1
- pfrsqrt
- pfsub
- pfsubr
- pi2fd
-
-
- pmulhrw
- pswapd
- Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
+
+Home
+| Search
+| D
+
+
+Last update Thu May 19 2005
+
+
+
+D x86 Inline Assembler
+
+
+
+
+
+ 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.
+
+ 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.
+ 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.
+
+
+
+
Special Cases
+
+
+
+
+
+
+ asm
+ {
+ rep ;
+ movsb ;
+ }
+
+
+
+ {
+ rep ;
+ nop ;
+ }
+
+ which produces the same result.
+
+
+ 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
+
+
+
+
+
+
+ jmp $ ;
+
+ branches to the instruction following the jmp instruction.
+ Opcodes Supported
+
+
+
+
+
+ aaa
+ aad
+ aam
+ aas
+ adc
+
+ add
+ addpd
+ addps
+ addsd
+ addss
+
+ and
+ andnpd
+ andnps
+ andpd
+ andps
+
+ arpl
+ bound
+ bsf
+ bsr
+ bswap
+
+ bt
+ btc
+ btr
+ bts
+ call
+
+ cbw
+ cdq
+ clc
+ cld
+ clflush
+
+ cli
+ clts
+ cmc
+ cmova
+ cmovae
+
+ cmovb
+ cmovbe
+ cmovc
+ cmove
+ cmovg
+
+ cmovge
+ cmovl
+ cmovle
+ cmovna
+ cmovnae
+
+ cmovnb
+ cmovnbe
+ cmovnc
+ cmovne
+ cmovng
+
+ cmovnge
+ cmovnl
+ cmovnle
+ cmovno
+ cmovnp
+
+ cmovns
+ cmovnz
+ cmovo
+ cmovp
+ cmovpe
+
+ cmovpo
+ cmovs
+ cmovz
+ cmp
+ cmppd
+
+ cmpps
+ cmps
+ cmpsb
+ cmpsd
+ cmpss
+
+ cmpsw
+ cmpxch8b
+ cmpxchg
+ comisd
+ comiss
+
+ cpuid
+ cvtdq2pd
+ cvtdq2ps
+ cvtpd2dq
+ cvtpd2pi
+
+ cvtpd2ps
+ cvtpi2pd
+ cvtpi2ps
+ cvtps2dq
+ cvtps2pd
+
+ cvtps2pi
+ cvtsd2si
+ cvtsd2ss
+ cvtsi2sd
+ cvtsi2ss
+
+ cvtss2sd
+ cvtss2si
+ cvttpd2dq
+ cvttpd2pi
+ cvttps2dq
+
+ cvttps2pi
+ cvttsd2si
+ cvttss2si
+ cwd
+ cwde
+
+ da
+ daa
+ das
+ db
+ dd
+
+ de
+ dec
+ df
+ di
+ div
+
+ divpd
+ divps
+ divsd
+ divss
+ dl
+
+ dq
+ ds
+ dt
+ dw
+ emms
+
+ enter
+ f2xm1
+ fabs
+ fadd
+ faddp
+
+ fbld
+ fbstp
+ fchs
+ fclex
+ fcmovb
+
+ fcmovbe
+ fcmove
+ fcmovnb
+ fcmovnbe
+ fcmovne
+
+ fcmovnu
+ fcmovu
+ fcom
+ fcomi
+ fcomip
+
+ fcomp
+ fcompp
+ fcos
+ fdecstp
+ fdisi
+
+ fdiv
+ fdivp
+ fdivr
+ fdivrp
+ feni
+
+ ffree
+ fiadd
+ ficom
+ ficomp
+ fidiv
+
+ fidivr
+ fild
+ fimul
+ fincstp
+ finit
+
+ fist
+ fistp
+ fisub
+ fisubr
+ fld
+
+ fld1
+ fldcw
+ fldenv
+ fldl2e
+ fldl2t
+
+ fldlg2
+ fldln2
+ fldpi
+ fldz
+ fmul
+
+ fmulp
+ fnclex
+ fndisi
+ fneni
+ fninit
+
+ fnop
+ fnsave
+ fnstcw
+ fnstenv
+ fnstsw
+
+ fpatan
+ fprem
+ fprem1
+ fptan
+ frndint
+
+ frstor
+ fsave
+ fscale
+ fsetpm
+ fsin
+
+ fsincos
+ fsqrt
+ fst
+ fstcw
+ fstenv
+
+ fstp
+ fstsw
+ fsub
+ fsubp
+ fsubr
+
+ fsubrp
+ ftst
+ fucom
+ fucomi
+ fucomip
+
+ fucomp
+ fucompp
+ fwait
+ fxam
+ fxch
+
+ fxrstor
+ fxsave
+ fxtract
+ fyl2x
+ fyl2xp1
+
+ hlt
+ idiv
+ imul
+ in
+ inc
+
+ ins
+ insb
+ insd
+ insw
+ int
+
+ into
+ invd
+ invlpg
+ iret
+ iretd
+
+ ja
+ jae
+ jb
+ jbe
+ jc
+
+ jcxz
+ je
+ jecxz
+ jg
+ jge
+
+ jl
+ jle
+ jmp
+ jna
+ jnae
+
+ jnb
+ jnbe
+ jnc
+ jne
+ jng
+
+ jnge
+ jnl
+ jnle
+ jno
+ jnp
+
+ jns
+ jnz
+ jo
+ jp
+ jpe
+
+ jpo
+ js
+ jz
+ lahf
+ lar
+
+ ldmxcsr
+ lds
+ lea
+ leave
+ les
+
+ lfence
+ lfs
+ lgdt
+ lgs
+ lidt
+
+ lldt
+ lmsw
+ lock
+ lods
+ lodsb
+
+ lodsd
+ lodsw
+ loop
+ loope
+ loopne
+
+ loopnz
+ loopz
+ lsl
+ lss
+ ltr
+
+ maskmovdqu
+ maskmovq
+ maxpd
+ maxps
+ maxsd
+
+ maxss
+ mfence
+ minpd
+ minps
+ minsd
+
+ minss
+ mov
+ movapd
+ movaps
+ movd
+
+ movdq2q
+ movdqa
+ movdqu
+ movhlps
+ movhpd
+
+ movhps
+ movlhps
+ movlpd
+ movlps
+ movmskpd
+
+ movmskps
+ movntdq
+ movnti
+ movntpd
+ movntps
+
+ movntq
+ movq
+ movq2dq
+ movs
+ movsb
+
+ movsd
+ movss
+ movsw
+ movsx
+ movupd
+
+ movups
+ movzx
+ mul
+ mulpd
+ mulps
+
+ mulsd
+ mulss
+ neg
+ nop
+ not
+
+ or
+ orpd
+ orps
+ out
+ outs
+
+ outsb
+ outsd
+ outsw
+ packssdw
+ packsswb
+
+ packuswb
+ paddb
+ paddd
+ paddq
+ paddsb
+
+ paddsw
+ paddusb
+ paddusw
+ paddw
+ pand
+
+ pandn
+ pavgb
+ pavgw
+ pcmpeqb
+ pcmpeqd
+
+ pcmpeqw
+ pcmpgtb
+ pcmpgtd
+ pcmpgtw
+ pextrw
+
+ pinsrw
+ pmaddwd
+ pmaxsw
+ pmaxub
+ pminsw
+
+ pminub
+ pmovmskb
+ pmulhuw
+ pmulhw
+ pmullw
+
+ pmuludq
+ pop
+ popa
+ popad
+ popf
+
+ popfd
+ por
+ prefetchnta
+ prefetcht0
+ prefetcht1
+
+ prefetcht2
+ psadbw
+ pshufd
+ pshufhw
+ pshuflw
+
+ pshufw
+ pslld
+ pslldq
+ psllq
+ psllw
+
+ psrad
+ psraw
+ psrld
+ psrldq
+ psrlq
+
+ psrlw
+ psubb
+ psubd
+ psubq
+ psubsb
+
+ psubsw
+ psubusb
+ psubusw
+ psubw
+ punpckhbw
+
+ punpckhdq
+ punpckhqdq
+ punpckhwd
+ punpcklbw
+ punpckldq
+
+ punpcklqdq
+ punpcklwd
+ push
+ pusha
+ pushad
+
+ pushf
+ pushfd
+ pxor
+ rcl
+ rcpps
+
+ rcpss
+ rcr
+ rdmsr
+ rdpmc
+ rdtsc
+
+ rep
+ repe
+ repne
+ repnz
+ repz
+
+ ret
+ retf
+ rol
+ ror
+ rsm
+
+ rsqrtps
+ rsqrtss
+ sahf
+ sal
+ sar
+
+ sbb
+ scas
+ scasb
+ scasd
+ scasw
+
+ seta
+ setae
+ setb
+ setbe
+ setc
+
+ sete
+ setg
+ setge
+ setl
+ setle
+
+ setna
+ setnae
+ setnb
+ setnbe
+ setnc
+
+ setne
+ setng
+ setnge
+ setnl
+ setnle
+
+ setno
+ setnp
+ setns
+ setnz
+ seto
+
+ setp
+ setpe
+ setpo
+ sets
+ setz
+
+ sfence
+ sgdt
+ shl
+ shld
+ shr
+
+ shrd
+ shufpd
+ shufps
+ sidt
+ sldt
+
+ smsw
+ sqrtpd
+ sqrtps
+ sqrtsd
+ sqrtss
+
+ stc
+ std
+ sti
+ stmxcsr
+ stos
+
+ stosb
+ stosd
+ stosw
+ str
+ sub
+
+ subpd
+ subps
+ subsd
+ subss
+ sysenter
+
+ sysexit
+ test
+ ucomisd
+ ucomiss
+ ud2
+
+ unpckhpd
+ unpckhps
+ unpcklpd
+ unpcklps
+ verr
+
+ verw
+ wait
+ wbinvd
+ wrmsr
+ xadd
+
+ xchg
+ xlat
+ xlatb
+ xor
+ xorpd
+
+
+ xorps
+
+
+
+
+ Pentium 4 (Prescott) Opcodes Supported
+
+
+
+
+
+ addsubpd
+ addsubps
+ fisttp
+ haddpd
+ haddps
+
+ hsubpd
+ hsubps
+ lddqu
+ monitor
+ movddup
+
+
+ movshdup
+ movsldup
+ mwait
+
+
+
+ AMD Opcodes Supported
+
+
+
+
+
+ pavgusb
+ pf2id
+ pfacc
+ pfadd
+ pfcmpeq
+
+ pfcmpge
+ pfcmpgt
+ pfmax
+ pfmin
+ pfmul
+
+ pfnacc
+ pfpnacc
+ pfrcp
+ pfrcpit1
+ pfrcpit2
+
+ pfrsqit1
+ pfrsqrt
+ pfsub
+ pfsubr
+ pi2fd
+
+
+ pmulhrw
+ pswapd
+ Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-[Home]
-[Search]
-[D]
-
-
-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.
- 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.
-
- 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.
-
-
-
-
- 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.
- Data Type Compatibility
-
-
-
-
-
-
-
- D type
- C type
-
-
-
- void
- void
-
-
-
- bit
- no equivalent
-
-
-
- byte
- signed char
-
-
-
- ubyte
- unsigned char
-
-
-
- char
- char (chars are unsigned in D)
-
-
-
- wchar
- wchar_t (when sizeof(wchar_t) is 2)
-
-
-
- dchar
- wchar_t (when sizeof(wchar_t) is 4)
-
-
-
- short
- short
-
-
-
- ushort
- unsigned short
-
-
-
- int
- int
-
-
-
- uint
- unsigned
-
-
-
- long
- long long
-
-
-
- ulong
- unsigned long long
-
-
-
- float
- float
-
-
-
- double
- double
-
-
-
- real
- long double
-
-
-
- ifloat
- float _Imaginary
-
-
-
- idouble
- double _Imaginary
-
-
-
- ireal
- long double _Imaginary
-
-
-
- cfloat
- float _Complex
-
-
-
- cdouble
- double _Complex
-
-
-
- creal
- long double _Complex
-
-
-
- struct
- struct
-
-
-
- union
- union
-
-
-
- enum
- enum
-
-
-
- class
- no 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
- 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.
- Structs and Unions
-
- D structs and unions are analogous to C's.
- 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.
- Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright (c) 1999-2005 by Digital Mars, All Rights Reserved
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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.
+ 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.
+
+
+
+ extern (C) int strcmp(char* string1, char* string2);
+
+
+
+ import std.string;
+ int myDfunction(char[] s)
+ {
+ return strcmp(std.string.toStringz(s), "foo");
+ }
+
+
+
+ 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.
+
+
+
+
+ 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.
+ Data Type Compatibility
+
+
+
+
+
+
+
+ D type
+ C type
+
+
+
+ void
+ void
+
+
+
+ bit
+ no equivalent
+
+
+
+ byte
+ signed char
+
+
+
+ ubyte
+ unsigned char
+
+
+
+ char
+ char (chars are unsigned in D)
+
+
+
+ wchar
+ wchar_t (when sizeof(wchar_t) is 2)
+
+
+
+ dchar
+ wchar_t (when sizeof(wchar_t) is 4)
+
+
+
+ short
+ short
+
+
+
+ ushort
+ unsigned short
+
+
+
+ int
+ int
+
+
+
+ uint
+ unsigned
+
+
+
+ long
+ long long
+
+
+
+ ulong
+ unsigned long long
+
+
+
+ float
+ float
+
+
+
+ double
+ double
+
+
+
+ real
+ long double
+
+
+
+ ifloat
+ float _Imaginary
+
+
+
+ idouble
+ double _Imaginary
+
+
+
+ ireal
+ long double _Imaginary
+
+
+
+ cfloat
+ float _Complex
+
+
+
+ cdouble
+ double _Complex
+
+
+
+ creal
+ long double _Complex
+
+
+
+ struct
+ struct
+
+
+
+ union
+ union
+
+
+
+ enum
+ enum
+
+
+
+ class
+ no 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
+ 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);
+ }
+ Structs and Unions
+
+ D structs and unions are analogous to C's.
+ 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.
+ Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-[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
-
-
-
- "D Language Perfect Guide"
- Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
+
+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
+
+
+
+ "D Language Perfect Guide"
+ Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-
-[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.
-
-
-
-
-
-
-
- The source file is checked to see what character set it is,
- and the appropriate scanner is loaded. ASCII and UTF
- formats are accepted.
-
-
-
- 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.
-
-
-
- The sequence of tokens is parsed to form syntax trees.
-
-
-
- The syntax trees are traversed to declare variables, load symbol tables, assign
- types, and in general determine the meaning of the program.
-
-
-
- Optimization is an optional pass that tries to rewrite the program
- in a semantically equivalent, but faster executing, version.
-
-
-
- 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
- >> 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:
-
-
-
- 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.
-
- 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'
-
-
-