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 @@ - -
-- - 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 -
- - - - + + + + + + + + + + + + + + + + + + + +
+ ++ + 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 @@ - - - -- 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 - -
- - - - + + + + + + + + + + + + + + + + + + + +
+ ++ 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 @@ - - - - - -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; - } -- -
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 @@ - - - - - -- 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.' - -
- - - - + + + + + + + + + + + + + + + + + + + +
+ +
+ + 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 @@ - - - - - -- -
- -
- -
- -
---
-- 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 --
+ +
+ +
+ +
+ +
+ +
+++
+- 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 @@ - - - - - -- - 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: - -
+ + 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 @@ - - -- 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.
-
-
-
- - - + + + + + + + + + + + + + + + + + + + +
+ +
+ + 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 @@ - - -- - 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
-
- -
- - - - - + + + + + + + + + + + + + + + + + + + +
+ ++ + 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 @@ - - -- - 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; - } -- - -
- - - - - + + + + + + + + + + + + + + + + + + + +
+ ++ + 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 @@ - - - - - -- -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 - } -- - -
- - - + + + + + + + + + + + + + + + + + + + + +
+ ++ +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 @@ - - - - -- -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. - - -
- - - + + + + + + + + + + + + + + + + + + + +
+ ++ +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 @@ - - -- - Building contract support into the language makes for: - -
- 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. - - - -
- - - - + + + + + + + + + + + + + + + + + + + +
+ ++ + Building contract support into the language makes for: + +
+ + 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 @@ - - - -- - 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" -- -
- - - - + + + + + + + + + + + + + + + + + + + +
+ ++ + 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 @@ - - - - - -- 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. - -
- - - + + + + + + + + + + + + + + + + + + + +
+ +
+ + 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 @@ - - - - - - - - - - - - -- - - - - - - - - - - - - -
- - Corto's - D button images: - - - -
- If you'd like to contribute more images, please - email - them to Digital Mars! - -
- - -
- Copyright (c) 1999-2005 by Digital Mars, All Rights Reserved - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + 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 @@ - - - - - -- - 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...- - -
+ + 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 @@ - - - - - -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** -- -
+ + 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 @@ - - -- - 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 | ♦ - - |
- - - - + + + + + + + + + + + + + + + + + + + +
+ ++ + 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 @@ - - - - -
-- 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 -- -
- - - - + + + + + + + + + + + + + + + + + + + +
+ ++ 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 @@ - - - - - -- -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? - -
+ +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 @@ - - - - - -- - 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. - -
+ + 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 @@ - - - - - -- -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. - - - - -
+ +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 @@ - - - - - -- - 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" ":
-
-
-
- Hex strings allow string literals to be created using hex data:
-
-
-
- Adjacent strings are concatenated with the ~ operator, or by simple
- juxtaposition:
-
-
- Decimal integers are a sequence of decimal digits.
-
- Binary integers are a sequence of binary digits preceded
- by a '0b'.
-
- Octal integers are a sequence of octal digits preceded by a '0'.
-
- Hexadecimal integers are a sequence of hexadecimal digits preceded
- by a '0x' or followed by an 'h'.
-
- Integers can have embedded '_' characters, which are ignored.
- The embedded '_' are useful for formatting long literals, such
- as using them as a thousands separator:
-
- The type of the integer is resolved as follows:
-
-
-
-
- Hexadecimal floats are preceded with a 0x and the
- exponent is a p
- or P followed by a decimal number serving as the exponent
- of 2.
-
-
- Floating literals can have embedded '_' characters, which are ignored.
- The embedded '_' are useful for formatting long literals to
- make them more readable, such
- as using them as a thousands separator:
-
-
- If a floating literal is followed by i or I, then it is an
- ireal (imaginary) type.
-
-
- Examples:
-
-
-
- Complex literals are not tokens, but are assembled from
- real and imaginary expressions in the semantic analysis:
-
-
-
-
-
-
-
- There is currently only one special token sequence, #line.
-
-
-
- For example:
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ The source text is terminated by whichever comes first.
+
+
+
+ There is no backslash line splicing, nor are there any limits
+ on the length of a line.
+
+
+
+ White space is defined as a sequence of one or more of spaces,
+ tabs, vertical tabs, form feeds, end of lines, or comments.
+
+
+
+ D has three kinds of comments:
+
+
+
+
+
+ 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.
+
+
+
+ A string literal is either a double quoted string, a wysiwyg quoted
+ string, an escape sequence, or a hex string.
+
+
+ Wysiwyg quoted strings are enclosed by r" and ".
+ All characters between
+ the r" and " are part of the string except for EndOfLine which is
+ regarded as a single \n character.
+ There are no escape sequences inside r" ":
+
+
+
+ Hex strings allow string literals to be created using hex data:
+
+
+
+ Adjacent strings are concatenated with the ~ operator, or by simple
+ juxtaposition:
+
+
+
+ Character literals are a single character or escape sequence
+ enclosed by single quotes, ' '.
+
+
+
+ Integers can be specified in decimal, binary, octal, or hexadecimal.
+
+ Decimal integers are a sequence of decimal digits.
+
+ Binary integers are a sequence of binary digits preceded
+ by a '0b'.
+
+ Octal integers are a sequence of octal digits preceded by a '0'.
+
+ Hexadecimal integers are a sequence of hexadecimal digits preceded
+ by a '0x' or followed by an 'h'.
+
+ Integers can have embedded '_' characters, which are ignored.
+ The embedded '_' are useful for formatting long literals, such
+ as using them as a thousands separator:
+
+ The type of the integer is resolved as follows:
+
+
+
+
+ Floats can be in decimal or hexadecimal format,
+ as in standard C.
+
+
+ Hexadecimal floats are preceded with a 0x and the
+ exponent is a p
+ or P followed by a decimal number serving as the exponent
+ of 2.
+
+
+ Floating literals can have embedded '_' characters, which are ignored.
+ The embedded '_' are useful for formatting long literals to
+ make them more readable, such
+ as using them as a thousands separator:
+
+
+ If a floating literal is followed by i or I, then it is an
+ ireal (imaginary) type.
+
+
+ Examples:
+
+
+
+ Complex literals are not tokens, but are assembled from
+ real and imaginary expressions in the semantic analysis:
+
+
+
+
+
+
+
+
+
+ There is currently only one special token sequence, #line.
+
+
+
+ This sets the source line number to Integer,
+ and optionally the source file name to Filespec,
+ beginning with the next line of source text.
+ The source file and line number is used for printing error messages
+ and for mapping generated code back to the source for the symbolic
+ debugging output.
+
+
+ For example:
+
+
+
+ Note that the backslash character is not treated specially inside
+ Filespec strings.
+
+
+ Last update Aug 13, 2004
-
-
- The three primary methods for allocating memory in D are:
-
-
-
- If a copy of s[] was always made by toupper(), then that will
- unnecessarily consume time and memory for strings that are already
- all upper case.
-
-
- The solution is to implement copy-on-write, which means that a copy
- is made only if the string needs to be modified. Some string
- processing languages do do this as the default behavior, but there
- is a huge cost to it. The string "abcdeF" will wind up being copied 5
- times by the function. To get the maximum efficiency using the protocol,
- it'll have to be done explicitly in the code. Here's toupper()
- rewritten to implement copy-on-write in an efficient manner:
-
-
-
- D doesn't provide any automated support for reference counting,
- it will have to be done explicitly.
-
-
- Win32 COM programming
- uses the members AddRef() and Release()
- to maintain the reference counts.
-
-
-
- To have a class allocated on the stack that has a destructor, this
- is the same as a declaration with the
- auto attribute.
- Although the current implementation does not put such objects on
- the stack, future ones can.
-
-
-
- Uninitialized data on the stack comes with some caveats that need
- to be carefully evaluated before using:
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The three primary methods for allocating memory in D are:
+
+
+
+ Note that the caller's version of s[] is also modified. This may
+ be not at all what was intended, or worse, s[] may be a slice
+ into a read-only section of memory.
+
+
+ If a copy of s[] was always made by toupper(), then that will
+ unnecessarily consume time and memory for strings that are already
+ all upper case.
+
+
+ The solution is to implement copy-on-write, which means that a copy
+ is made only if the string needs to be modified. Some string
+ processing languages do do this as the default behavior, but there
+ is a huge cost to it. The string "abcdeF" will wind up being copied 5
+ times by the function. To get the maximum efficiency using the protocol,
+ it'll have to be done explicitly in the code. Here's toupper()
+ rewritten to implement copy-on-write in an efficient manner:
+
+
+
+ Copy-on-write is the protocol implemented by array processing
+ functions in the D Phobos runtime library.
+
+
+
+ Such free list approaches can be very high performance.
+
+
+
+ D doesn't provide any automated support for reference counting,
+ it will have to be done explicitly.
+
+
+ Win32 COM programming
+ uses the members AddRef() and Release()
+ to maintain the reference counts.
+
+
+
+ The critical features of new() are:
+
+
+
+
+
+ To have a class allocated on the stack that has a destructor, this
+ is the same as a declaration with the
+ auto attribute.
+ Although the current implementation does not put such objects on
+ the stack, future ones can.
+
+
+
+
+
+ will not be as fast as it might be since the buffer[] contents
+ are always initialized. If careful profiling of the program shows
+ that this initialization is a speed problem, it can be eliminated using
+ the following idiom:
+
+
+
+ A good D implementation will recognize that alloca() is called with
+ a constant size argument, and so can be replaced with an uninitialized
+ array of the same size allocated on the stack. This will produce
+ execution performance equivalent to using an uninitialized stack
+ array in C.
+
+
+ Uninitialized data on the stack comes with some caveats that need
+ to be carefully evaluated before using:
+
+
+
-
- Unlike a template instantiation, a template mixin's body is evaluated
- within the scope where the mixin appears, not where the template declaration
- is defined. It is analogous to cutting and pasting the body of
- the template into the location of the mixin. It is useful for injecting
- parameterized 'boilerplate' code, as well as for creating
- templated nested functions, which is not possible with
- template instantiations.
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Unlike a template instantiation, a template mixin's body is evaluated
+ within the scope where the mixin appears, not where the template declaration
+ is defined. It is analogous to cutting and pasting the body of
+ the template into the location of the mixin. It is useful for injecting
+ parameterized 'boilerplate' code, as well as for creating
+ templated nested functions, which is not possible with
+ template instantiations.
+
+
+
+ Mixins can be parameterized:
+
+
+
+ Mixins can add virtual functions to a class:
+
+
+
+ Mixins are evaluted in the scope of where they appear, not the scope
+ of the template declaration:
+
+
+
+ Mixins can parameterize symbols using alias parameters:
+
+
+
+ This example uses a mixin to implement a generic Duff's device
+ for an arbitrary statement (in this case, the arbitrary statement
+ is in bold). A nested function is generated as well as a
+ delegate literal, these can be inlined by the compiler:
+
+
+
+
+
+ If two different mixins are put in the same scope, and each
+ define a declaration with the same name, there is an ambiguity
+ error when the declaration is referenced:
+
+
+
+ If a mixin has a MixinIdentifier, it can be used to
+ disambiguate:
+
+
+
+ A mixin has its own scope, even if a declaration is overridden
+ by the enclosing one:
+
+
+
+
+
-
- Modules automatically provide a namespace scope for their contents.
- Modules superficially resemble classes, but differ in that:
-
-
-
- If present, the ModuleDeclaration appears syntactically first
- in the source file, and there can be only one per source file.
-
-
- Example:
-
-
-
- Example:
-
-
-
- For example, assume the following modules:
-
-
-
- Cycles (circular dependencies) in the import declarations are
- allowed as long as not both of the modules contain static constructors
- or static destructors. Violation of this rule will result
- in a runtime exception.
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Modules have a one-to-one correspondence with source files.
+ The module name is the file name with the path and extension
+ stripped off.
+
+
+ Modules automatically provide a namespace scope for their contents.
+ Modules superficially resemble classes, but differ in that:
+
+
+
+ The Identifier preceding the rightmost are the packages
+ that the module is in. The packages correspond to directory names in
+ the source file path.
+
+
+ If present, the ModuleDeclaration appears syntactically first
+ in the source file, and there can be only one per source file.
+
+
+ Example:
+
+
+
+ By convention, package and module names are all lower case. This is
+ because those names have a one-to-one correspondence with the operating
+ system's directory and file names, and many file systems
+ are not case sensitive. All lower case package and module names will
+ minimize problems moving projects between dissimilar file systems.
+
+
+
+ The rightmost Identifier becomes the module name.
+ The top level scope in the module is merged with the current scope.
+
+
+ Example:
+
+
+
+
+
+ For example, assume the following modules:
+
+
+
+ then:
+
+
+
+ and:
+
+
+
+ and:
+
+
+
+ and:
+
+
+
+ If the import is private, such as:
+
+
+
+ then def is not searched when another module imports abc.
+
+
+
+ The leading '.' means look up the name at the module scope level.
+
+
+
+ Cycles (circular dependencies) in the import declarations are
+ allowed as long as not both of the modules contain static constructors
+ or static destructors. Violation of this rule will result
+ in a runtime exception.
+
+
+
-
-
- Given a unary
- overloadable operator op and its corresponding
- class or struct member
- function name opfunc, the syntax:
-
-
-
- Given a binary
- overloadable operator op and its corresponding
- class or struct member
- function name opfunc and opfunc_r,
- and the syntax:
-
-
-
-
-
- The member function opEquals() is defined as part of Object
- as:
-
-
-
- If a struct has no opEquals() function declared for it,
- a bit compare of the contents of the two structs is done to
- determine equality or inequality.
-
-
-
- The member function opCmp() is defined as part of Object
- as:
-
-
-
- If a struct has no opCmp() function declared for it, attempting
- to compare two structs is an error.
-
-
- Note: Comparing a reference to a class object against null
- should be done as:
-
-
- Note: Array index overloading currently does not
- work for the lvalue of an op=, ++, or -- operator.
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Given a unary
+ overloadable operator op and its corresponding
+ class or struct member
+ function name opfunc, the syntax:
+
+
+
+ Given a binary
+ overloadable operator op and its corresponding
+ class or struct member
+ function name opfunc and opfunc_r,
+ and the syntax:
+
+
+
+
+
+ The member function opEquals() is defined as part of Object
+ as:
+
+
+
+ If a struct has no opEquals() function declared for it,
+ a bit compare of the contents of the two structs is done to
+ determine equality or inequality.
+
+
+
+ The member function opCmp() is defined as part of Object
+ as:
+
+
+
+ If a struct has no opCmp() function declared for it, attempting
+ to compare two structs is an error.
+
+
+ Note: Comparing a reference to a class object against null
+ should be done as:
+
+
+ Note: Array index overloading currently does not
+ work for the lvalue of an op=, ++, or -- operator.
+
+
+
+
+
+
+
+
diff -uNr dmd-0.123/dmd/html/d/overview.html dmd-0.124/dmd/html/d/overview.html
--- dmd-0.123/dmd/html/d/overview.html 2005-04-29 01:05:22.000000000 +0200
+++ dmd-0.124/dmd/html/d/overview.html 2005-05-19 11:44:48.000000000 +0200
@@ -1,938 +1,958 @@
-
-
-
-
-
-
- D is not a scripting language, nor an interpreted language. It doesn't
- come with a VM,
- a religion, or an overriding
- philosophy. It's a practical language for practical programmers
- who need to get the job done quickly, reliably, and leave behind
- maintainable, easy to understand code.
-
-
- D is the culmination of decades of experience implementing
- compilers for many diverse languages, and attempting to construct
- large projects using those languages. D draws inspiration from
- those other languages (most especially C++) and tempers it with
- experience and real world practicality.
-
-
-
-
-
- The software industry has come a long way since the C language was
- invented.
- Many new concepts were added to the language with C++, but backwards
- compatibility with C was maintained, including compatibility with
- nearly all the weaknesses of the original design.
- There have been many attempts to fix those weaknesses, but the
- compatibility issue frustrates it.
- Meanwhile, both C and C++ undergo a constant accretion of new
- features. These new features must be carefully fitted into the
- existing structure without requiring rewriting old code.
- The end result is very complicated - the C standard is nearly
- 500 pages, and the C++ standard is about 750 pages!
- C++ is a difficult and costly language to implement,
- resulting in implementation variations that make it frustrating
- to write fully portable C++ code.
-
-
- C++ programmers tend to program in particular islands of the language,
- i.e. getting very proficient using certain features while avoiding
- other feature sets. While the code is usually portable from compiler
- to compiler, it can be hard to port it from programmer to programmer.
- A great strength of C++ is that it can support many radically
- different styles of programming - but in long term use, the
- overlapping and contradictory styles are a hindrance.
-
-
- C++ implements things like resizable arrays and string concatenation
- as part of the standard library, not as part of the core language.
- Not being part of the core language has several
- suboptimal consequences.
-
-
- Can the power and capability of C++ be extracted, redesigned,
- and recast into a language that is simple, orthogonal,
- and practical?
- Can it all be put into a package
- that is easy for compiler
- writers to correctly implement, and
- which enables compilers to efficiently generate aggressively
- optimized code?
-
-
- Modern compiler technology has progressed to the point where language
- features for the purpose of compensating for primitive compiler
- technology can be omitted. (An
- example of this would be the 'register' keyword in C, a more
- subtle example is the macro
- preprocessor in C.)
- We can rely on modern compiler optimization technology to not
- need language features necessary to get acceptable code quality out of
- primitive compilers.
-
-
-
-
- Using D will not mean that the programmer will become restricted to a
- specialized runtime vm (virtual machine) like the Java vm or the
- Smalltalk vm.
- There is no D vm, it's a straightforward compiler that generates
- linkable object files.
- D connects to the operating system just like C does.
- The usual familiar tools like make will fit right in with
- D development.
-
-
-
- Example:
-
-
-
- Such makes it possible for D to directly interface to a
- wider variety of foreign API's. There would be no need for
- workarounds like "Interface Definition Languages".
-
-
-
- There's a perception that garbage collection is for lazy, junior
- programmers. I remember when that was said about C++, after all,
- there's nothing in C++ that cannot be done in C, or in assembler
- for that matter.
-
-
- Garbage collection eliminates the tedious, error prone memory allocation
- tracking code necessary in C and C++. This not only means much
- faster development time and lower maintenance costs,
- but the resulting program frequently runs
- faster!
-
-
- Sure, garbage collectors can be used with C++, and I've used them
- in my own C++ projects. The language isn't friendly to collectors,
- however, impeding the effectiveness of it. Much of the runtime
- library code can't be used with
- collectors.
-
-
- For a fuller discussion of this, see garbage
- collection.
-
-
-
- Many D implementations will also support intrinsic functions
- analogously to C's support of intrinsics for I/O port manipulation,
- direct access to special floating point operations, etc.
-
-
-
-
- Unit tests can be done in other languages, but the result is kludgy
- and the languages just aren't accommodating of the concept.
- Unit testing is a main feature of D. For library functions it works
- out great, serving both to guarantee that the functions
- actually work and to illustrate how to use the functions.
-
-
- Consider the many C++ library and application code bases out there for
- download on the web. How much of it comes with *any* verification
- tests at all, let alone unit testing? Less than 1%? The usual practice
- is if it compiles, we assume it works. And we wonder if the warnings
- the compiler spits out in the process are real bugs or just nattering
- about nits.
-
-
- Along with Contract Programming, unit testing makes D far and away
- the best language for writing reliable, robust systems applications.
- Unit testing also gives us a quick-and-dirty estimate of the quality
- of some unknown piece of D code dropped in our laps - if it has no
- unit tests and no contracts, it's unacceptable.
-
-
-
-
- The synchronize statement puts a mutex around a block of statements,
- controlling access either by object or globally.
-
-
-
-
+
+ D is not a scripting language, nor an interpreted language. It doesn't
+ come with a VM,
+ a religion, or an overriding
+ philosophy. It's a practical language for practical programmers
+ who need to get the job done quickly, reliably, and leave behind
+ maintainable, easy to understand code.
+
+
+ D is the culmination of decades of experience implementing
+ compilers for many diverse languages, and attempting to construct
+ large projects using those languages. D draws inspiration from
+ those other languages (most especially C++) and tempers it with
+ experience and real world practicality.
+
+
+
+
+
+ The software industry has come a long way since the C language was
+ invented.
+ Many new concepts were added to the language with C++, but backwards
+ compatibility with C was maintained, including compatibility with
+ nearly all the weaknesses of the original design.
+ There have been many attempts to fix those weaknesses, but the
+ compatibility issue frustrates it.
+ Meanwhile, both C and C++ undergo a constant accretion of new
+ features. These new features must be carefully fitted into the
+ existing structure without requiring rewriting old code.
+ The end result is very complicated - the C standard is nearly
+ 500 pages, and the C++ standard is about 750 pages!
+ C++ is a difficult and costly language to implement,
+ resulting in implementation variations that make it frustrating
+ to write fully portable C++ code.
+
+
+ C++ programmers tend to program in particular islands of the language,
+ i.e. getting very proficient using certain features while avoiding
+ other feature sets. While the code is usually portable from compiler
+ to compiler, it can be hard to port it from programmer to programmer.
+ A great strength of C++ is that it can support many radically
+ different styles of programming - but in long term use, the
+ overlapping and contradictory styles are a hindrance.
+
+
+ C++ implements things like resizable arrays and string concatenation
+ as part of the standard library, not as part of the core language.
+ Not being part of the core language has several
+ suboptimal consequences.
+
+
+ Can the power and capability of C++ be extracted, redesigned,
+ and recast into a language that is simple, orthogonal,
+ and practical?
+ Can it all be put into a package
+ that is easy for compiler
+ writers to correctly implement, and
+ which enables compilers to efficiently generate aggressively
+ optimized code?
+
+
+ Modern compiler technology has progressed to the point where language
+ features for the purpose of compensating for primitive compiler
+ technology can be omitted. (An
+ example of this would be the 'register' keyword in C, a more
+ subtle example is the macro
+ preprocessor in C.)
+ We can rely on modern compiler optimization technology to not
+ need language features necessary to get acceptable code quality out of
+ primitive compilers.
+
+
+
+
+ Using D will not mean that the programmer will become restricted to a
+ specialized runtime vm (virtual machine) like the Java vm or the
+ Smalltalk vm.
+ There is no D vm, it's a straightforward compiler that generates
+ linkable object files.
+ D connects to the operating system just like C does.
+ The usual familiar tools like make will fit right in with
+ D development.
+
+
+
+ Example:
+
+
+
+ Such makes it possible for D to directly interface to a
+ wider variety of foreign API's. There would be no need for
+ workarounds like "Interface Definition Languages".
+
+
+
+ There's a perception that garbage collection is for lazy, junior
+ programmers. I remember when that was said about C++, after all,
+ there's nothing in C++ that cannot be done in C, or in assembler
+ for that matter.
+
+
+ Garbage collection eliminates the tedious, error prone memory allocation
+ tracking code necessary in C and C++. This not only means much
+ faster development time and lower maintenance costs,
+ but the resulting program frequently runs
+ faster!
+
+
+ Sure, garbage collectors can be used with C++, and I've used them
+ in my own C++ projects. The language isn't friendly to collectors,
+ however, impeding the effectiveness of it. Much of the runtime
+ library code can't be used with
+ collectors.
+
+
+ For a fuller discussion of this, see garbage
+ collection.
+
+
+
+ Many D implementations will also support intrinsic functions
+ analogously to C's support of intrinsics for I/O port manipulation,
+ direct access to special floating point operations, etc.
+
+
+
+
+ Unit tests can be done in other languages, but the result is kludgy
+ and the languages just aren't accommodating of the concept.
+ Unit testing is a main feature of D. For library functions it works
+ out great, serving both to guarantee that the functions
+ actually work and to illustrate how to use the functions.
+
+
+ Consider the many C++ library and application code bases out there for
+ download on the web. How much of it comes with *any* verification
+ tests at all, let alone unit testing? Less than 1%? The usual practice
+ is if it compiles, we assume it works. And we wonder if the warnings
+ the compiler spits out in the process are real bugs or just nattering
+ about nits.
+
+
+ Along with Contract Programming, unit testing makes D far and away
+ the best language for writing reliable, robust systems applications.
+ Unit testing also gives us a quick-and-dirty estimate of the quality
+ of some unknown piece of D code dropped in our laps - if it has no
+ unit tests and no contracts, it's unacceptable.
+
+
+
+
+ The synchronize statement puts a mutex around a block of statements,
+ controlling access either by object or globally.
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- For conversion to signed types, the grammar recognized is:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The usual arithmetic operations can be performed on d_time,
- such as adding, subtracting, etc. Elapsed time in Ticks can
- be computed by subtracting a starting d_time from an ending
- d_time.
-
-
- An invalid value for d_time is represented by d_time.init.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Both return the bit number of the first set bit.
- The return value is undefined if v is zero.
-
-
- Example
-
- p is a non-NULL pointer to an array of uints.
- index is a bit number, starting with bit 0 of p[0],
- and progressing. It addresses bits like the expression:
-
-
- All return a non-zero value if the bit was set, and a zero
- if it was clear.
-
-
- Example
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-There are two ways to do this. The first does it all in one function call
-to sum(). The second is for when the data is buffered.
-
-The routines and algorithms are derived from the
-RSA Data Security, Inc. MD5 Message-Digest Algorithm.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The exact aliases are types of exactly the specified number of bits.
- The at least aliases are at least the specified number of bits
- large, and can be larger.
- The fast aliases are the fastest integral type supported by the
- processor that is at least as wide as the specified number of bits.
-
-
- The aliases are:
-
-
-
-
- The ptr aliases are integral types guaranteed to be large enough
- to hold a pointer without losing bits:
-
-
-
-
- The max aliases are the largest integral types:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Note: For Win32 systems, the C wchar_t type
- is UTF-16 and corresponds to the D wchar type.
- For linux systems, the C wchar_t type
- is UTF-32 and corresponds to the D utf.dchar type.
-
-
- UTF character support is restricted to (0 <= character <= 0x10FFFF).
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ For conversion to signed types, the grammar recognized is:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The usual arithmetic operations can be performed on d_time,
+ such as adding, subtracting, etc. Elapsed time in Ticks can
+ be computed by subtracting a starting d_time from an ending
+ d_time.
+
+
+ An invalid value for d_time is represented by d_time.init.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Both return the bit number of the first set bit.
+ The return value is undefined if v is zero.
+
+
+ Example
+
+ Output
+
+ p is a non-NULL pointer to an array of uints.
+ index is a bit number, starting with bit 0 of p[0],
+ and progressing. It addresses bits like the expression:
+
+
+ All return a non-zero value if the bit was set, and a zero
+ if it was clear.
+
+
+ Example
+
+
+
+ Output
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+There are two ways to do this. The first does it all in one function call
+to sum(). The second is for when the data is buffered.
+
+The routines and algorithms are derived from the
+RSA Data Security, Inc. MD5 Message-Digest Algorithm.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The exact aliases are types of exactly the specified number of bits.
+ The at least aliases are at least the specified number of bits
+ large, and can be larger.
+ The fast aliases are the fastest integral type supported by the
+ processor that is at least as wide as the specified number of bits.
+
+
+ The aliases are:
+
+
+
+
+ The ptr aliases are integral types guaranteed to be large enough
+ to hold a pointer without losing bits:
+
+
+
+
+ The max aliases are the largest integral types:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Note: For Win32 systems, the C wchar_t type
+ is UTF-16 and corresponds to the D wchar type.
+ For linux systems, the C wchar_t type
+ is UTF-32 and corresponds to the D utf.dchar type.
+
+
+ UTF character support is restricted to (0 <= character <= 0x10FFFF).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -uNr dmd-0.123/dmd/html/d/portability.html dmd-0.124/dmd/html/d/portability.html
--- dmd-0.123/dmd/html/d/portability.html 2005-04-15 14:13:42.000000000 +0200
+++ dmd-0.124/dmd/html/d/portability.html 2005-05-19 11:44:48.000000000 +0200
@@ -1,121 +1,145 @@
-
-
-
-
-
-
- In particular, function parameters can be evaluated either left to right
- or right to left, depending on the particular calling conventions
- used.
-
-
- If the operands of an associative operator + or * are floating
- point values, the expression is not reordered.
-
-
-
- Minor differences can be handled by constant defined in a system
- specific import, and then using that constant in an if
- statement.
-
-
+
+ In particular, function parameters can be evaluated either left to right
+ or right to left, depending on the particular calling conventions
+ used.
+
+
+ If the operands of an associative operator + or * are floating
+ point values, the expression is not reordered.
+
+
+
+ Minor differences can be handled by constant defined in a system
+ specific import, and then using that constant in an if
+ statement.
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pragmas are a way to pass special information to the compiler
+ and to add vendor specific extensions to D.
+ Pragmas can be used by themselves terminated with a ';',
+ they can influence a statement, a block of statements, a declaration, or
+ a block of declarations.
+
+
+
+ The kind of pragma it is is determined by the Identifier.
+ ExpressionList is a comma-separated list of
+ AssignExpressions. The AssignExpressions must be
+ parsable as expressions, but what they mean semantically
+ is up to the individual pragma semantics.
+
+
+
+
+
+
+
+
+ Compilers must diagnose an error for unrecognized Pragmas,
+ even if they are vendor specific ones. This implies that vendor
+ specific pragmas should be wrapped in version statements:
+
+
+
+
+
-
-
-
-
-
- These problems can be circumvented to some extent by defining a
- static_assert macro (thanks to M. Wilson):
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ or the more portable:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ D's optimizer will inline the function, and will do the conversion of the
+ string constant at compile time.
+
+
+
+
+
+
+
+
+
+
+ In declarations.h:
+
+
+
+
+
+
+
+
+ The compiler optimizer will inline it; no efficiency is lost.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This suffers from numerous problems:
+
+
+ The problems addressed are:
+
+
+ This has the limitations inherent in preprocessor expressions
+ (i.e. integer constant expressions only, no casts, no sizeof,
+ no symbolic constants, etc.).
+
+
+ These problems can be circumvented to some extent by defining a
+ static_assert macro (thanks to M. Wilson):
+
+
+
+ and using it like:
+
+
+
+ This works by causing a compile time semantic error if the condition
+ evaluates
+ to false. The limitations of this technique are a sometimes very
+ confusing error message from the compiler, along with an inability
+ to use a static_assert outside of a function body.
+
+
+
+
+ Last update Mar 8, 2005
-
-
- A simple property would be:
-
-
-
- In all the other respects, these methods are like any other methods.
- They can be static, have different linkages, be overloaded with
- methods with multiple parameters, have their address taken, etc.
-
-
- Note: Properties currently cannot be the lvalue of an
- op=, ++, or -- operator.
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A simple property would be:
+
+
+
+ To use it:
+
+
+
+ The absence of a read method means that the property is write-only.
+ The absence of a write method means that the property is read-only.
+ Multiple write methods can exist; the correct one is selected using
+ the usual function overloading rules.
+
+
+ In all the other respects, these methods are like any other methods.
+ They can be static, have different linkages, be overloaded with
+ methods with multiple parameters, have their address taken, etc.
+
+
+ Note: Properties currently cannot be the lvalue of an
+ op=, ++, or -- operator.
+
+
+
-
- Labels are in a name space independent of declarations, variables,
- types, etc.
- Even so, labels cannot have the same name as local declarations.
- The label name space is the body of the function
- they appear in. Label name spaces do not nest, i.e. a label
- inside a block statement is accessible from outside that block.
-
-
-
-
- The 'dangling else' parsing problem is solved by associating the
- else with the nearest if statement.
-
-
-
- A break statement will exit the loop. A continue statement
- will transfer directly to evaluating Expression again.
-
-
-
- A break statement will exit the loop. A continue statement
- will transfer directly to evaluationg Expression again.
-
-
-
- A break statement will exit the loop. A continue statement
- will transfer directly to the Increment.
-
-
- If Initializer declares a variable, that variable's scope
- extends through the end of Statement. For example:
-
-
-
- If the aggregate expression is a static or dynamic array, there
- can be one or two variables declared. If one, then the variable
- is said to be the value set to the elements of the array,
- one by one. The type of the
- variable must match the type of the array contents, except for the
- special cases outlined below.
- If there are
- two variables declared, the first is said to be the index
- and the second is said to be the value. The index
- must be of int or uint type, it cannot be inout,
- and it is set to be the index of the array element.
-
-
-
- If the aggregate is a struct or a class object, that struct
- or class must have an opApply function with the type:
-
-
-
- For example, consider a class that is a container for two elements:
-
-
-
- The case expressions, ExpressionList, are a comma separated
- list of expressions.
-
-
- If none of the case expressions match, and there is a default
- statement, the default statement is transferred to.
-
-
- If none of the case expressions match, and there is not a default
- statement, a SwitchError is thrown. The reason for this is
- to catch the common programming error of adding a new value to
- an enum, but failing to account for the extra value in
- switch statements. This behavior is unlike C or C++.
-
-
- The case expressions must all evaluate to a constant value
- or array, and be implicitly convertible to the type T of the
- switch Expression.
-
-
- Case expressions must all evaluate to distinct values.
- There may not be two or more default statements.
-
-
- Case statements and default statements associated with the switch
- can be nested within block statements; they do not have to be in
- the outermost block. For example, this is allowed:
-
-
-
- Note: Unlike C and C++, strings can be used in switch
- expressions. For example:
-
-
-
- Implementation Note: The compiler's code generator may
- assume that the case
- statements are sorted by frequency of use, with the most frequent
- appearing first and the least frequent last. Although this is
- irrelevant as far as program correctness is concerned, it is of
- performance interest.
-
-
-
-
- If continue is followed by Identifier, the Identifier
- must be the label of an enclosing while, for, or do
- loop, and the next iteration of that loop is executed.
- It is an error if
- there is no such statement.
-
-
- Any intervening finally clauses are executed, and any intervening
- synchronization objects are released.
-
-
- Note: If a finally clause executes a return, throw, or goto
- out of the finally clause,
- the continue target is never reached.
-
-
-
- If break is followed by Identifier, the Identifier
- must be the label of an enclosing while, for, do or switch
- statement, and that statement is exited. It is an error if
- there is no such statement.
-
-
- Any intervening finally clauses are executed, and any intervening
- synchronization objects are released.
-
-
- Note: If a finally clause executes a return, throw, or goto
- out of the finally clause,
- the break target is never reached.
-
-
-
- At least one return statement is required if the function
- specifies a return type that is not void.
-
-
- Expression is allowed even if the function specifies
- a void return type. The Expression will be evaluated,
- but nothing will be returned.
-
-
- Before the function actually returns, any enclosing finally
- clauses are executed, and any enclosing synchronization
- objects are released.
-
-
- The function will not return if any enclosing finally clause
- does a return, goto or throw that exits the finally clause.
-
-
- If there is an out postcondition (see Contract Programming),
- that postcondition is executed
- after the Expression is evaluated and before the function
- actually returns.
-
-
-
- The third form, goto case;, transfers to the
- next CaseStatement of the innermost enclosing
- SwitchStatement.
-
-
- The fourth form, goto case Expression;, transfers to the
- CaseStatement of the innermost enclosing SwitchStatement
- with a matching Expression.
-
-
- Any intervening finally clauses are executed, along with
- releasing any intervening synchronization mutexes.
-
-
- It is illegal for a goto to be used to skip initializations.
-
-
-
- For Symbol which is a scope or TemplateInstance,
- the corresponding scope is searched when looking up symbols.
- For example:
-
-
-
- synchronized (Expression), where Expression evaluates to an
- Object reference, allows only one thread at a time to use
- that Object to execute the Statement.
- If Expression is an instance of an Interface, it is
- cast to an Object.
-
-
- The synchronization gets released even if Statement terminates
- with an exception, goto, or return.
-
-
- Example:
-
-
-
- If just type T is given and no variable v, then the catch clause
- is still executed.
-
-
- It is an error if any CatchParameter type T1 hides
- a subsequent Catch with type T2, i.e. it is an error if
- T1 is the same type as or a base class of T2.
-
-
- LastCatch catches all exceptions.
-
-
- The FinallyStatement is always executed, whether
- the try BlockStatement exits with a goto, break,
- continue, return, exception, or fall-through.
-
-
- If an exception is raised in the FinallyStatement and
- is not caught before the FinallyStatement is executed,
- the new exception replaces any existing exception:
-
-
-
- A FinallyStatement may not contain any Catches.
- This restriction may be relaxed in future versions.
-
-
-
- A volatile statement does not guarantee atomicity. For that,
- use synchronized statements.
-
-
-
- The format of the instructions is, of course, highly dependent
- on the native instruction set of the target CPU, and so is
- implementation defined.
- But, the format will follow the following
- conventions:
-
-
-
- For example, for the Intel Pentium:
-
-
+
+
+
+ Any statement can be labelled, including empty statements,
+ and so can serve as the target
+ of a goto statement. Labelled statements can also serve as the
+ target of a break or continue statement.
+
+
+ Labels are in a name space independent of declarations, variables,
+ types, etc.
+ Even so, labels cannot have the same name as local declarations.
+ The label name space is the body of the function
+ they appear in. Label name spaces do not nest, i.e. a label
+ inside a block statement is accessible from outside that block.
+
+
+
+
+ A block statement introduces a new scope for local
+ symbols. A local symbol's name, however, must be unique within
+ the function.
+
+
+
+ The idea is to avoid bugs in complex functions caused by
+ scoped declarations inadvertantly hiding previous ones.
+ Local names should all be unique within a function.
+
+
+
+ Expressions that have no effect, like (x + x), are illegal
+ in expression statements.
+
+
+
+ If no AssignmentExpression is there to initialize the
+ variable, it is initialized to the default value for its type.
+
+
+
+ Expression is evaluated and must have a type that
+ can be converted to a boolean. If it's true the if
+ statement is transferred to, else the else statement
+ is transferred to.
+
+
+ The 'dangling else' parsing problem is solved by associating the
+ else with the nearest if statement.
+
+
+
+ Expression is evaluated and must have a type that
+ can be converted to a boolean. If it's true the
+ statement is executed. After the statement is executed,
+ the Expression is evaluated again, and if true the
+ statement is executed again. This continues until the
+ Expression evaluates to false.
+
+
+ A break statement will exit the loop. A continue statement
+ will transfer directly to evaluating Expression again.
+
+
+
+ Statement is executed. Then
+ Expression is evaluated and must have a type that
+ can be converted to a boolean. If it's true the
+ loop is iterated again.
+ This continues until the
+ Expression evaluates to false.
+
+
+ A break statement will exit the loop. A continue statement
+ will transfer directly to evaluationg Expression again.
+
+
+
+ Initializer is executed.
+ Test is evaluated and must have a type that
+ can be converted to a boolean. If it's true the
+ statement is executed. After the statement is executed,
+ the Increment is executed.
+ Then Test is evaluated again, and if true the
+ statement is executed again. This continues until the
+ Test evaluates to false.
+
+
+ A break statement will exit the loop. A continue statement
+ will transfer directly to the Increment.
+
+
+ If Initializer declares a variable, that variable's scope
+ extends through the end of Statement. For example:
+
+
+
+ is equivalent to:
+
+
+
+ Function bodies cannot be empty:
+
+
+
+ Use instead:
+
+
+
+ The Initializer may be omitted. Test may also be
+ omitted, and if so, it is treated as if it evaluated to true.
+
+
+
+ Expression is evaluated. It must evaluate to an aggregate
+ expression
+ of type static array, dynamic array, associative array,
+ struct, or class.
+ The Statement is executed, once for each element of the
+ aggregate expression.
+ At the start of each iteration, the variables declared by
+ the ForeachTypeList
+ are set to be a copy of the contents of the aggregate.
+ If the variable is inout, it is a reference to the
+ contents of that aggregate.
+
+
+ If the aggregate expression is a static or dynamic array, there
+ can be one or two variables declared. If one, then the variable
+ is said to be the value set to the elements of the array,
+ one by one. The type of the
+ variable must match the type of the array contents, except for the
+ special cases outlined below.
+ If there are
+ two variables declared, the first is said to be the index
+ and the second is said to be the value. The index
+ must be of int or uint type, it cannot be inout,
+ and it is set to be the index of the array element.
+
+
+
+ If the aggregate expression is a static or dynamic array of
+ chars, wchars, or dchars, then the Type of
+ the value
+ can be any of char, wchar, or dchar.
+ In this manner any UTF array
+ can be decoded into any UTF type:
+
+
+
+
+ If the aggregate expression is an associative array, there
+ can be one or two variables declared. If one, then the variable
+ is said to be the value set to the elements of the array,
+ one by one. The type of the
+ variable must match the type of the array contents. If there are
+ two variables declared, the first is said to be the index
+ and the second is said to be the value. The index
+ must be of the same type as the indexing type of the associative
+ array. It cannot be inout,
+ and it is set to be the index of the array element.
+
+
+
+ If the aggregate expression is a static or dynamic array, the
+ elements are iterated over starting at index 0 and continuing
+ to the maximum of the array. If it is an associative array,
+ the order of the elements is undefined. If it is a struct or
+ class object, it is defined by the special opApply member function.
+
+
+ If the aggregate is a struct or a class object, that struct
+ or class must have an opApply function with the type:
+
+
+
+ where Type matches the Type used in the foreach
+ declaration of Identifier. Multiple ForeachTypes
+ correspond with multiple Type's in the delegate type
+ passed to opApply.
+ There can be multiple opApply functions, one is selected
+ by matching the type of dg to the ForeachTypes
+ of the ForeachStatement.
+ The body of the opApply
+ function iterates over the elements it aggregates, passing them
+ each to the dg function. If the dg returns 0, then
+ opApply goes on to the next element.
+ If the dg returns a nonzero value, opApply must cease
+ iterating and return that value. Otherwise, after done iterating
+ across all the elements, opApply will return 0.
+
+
+ For example, consider a class that is a container for two elements:
+
+
+
+ An example using this might be:
+
+
+
+ which would print:
+
+
+
+ which would print:
+
+
+
+ which would print:
+
+
+
+ A BreakStatement in the body of the foreach will exit the
+ foreach, a ContinueStatement will immediately start the
+ next iteration.
+
+
+
+ Expression is evaluated. The result type T must be
+ of integral type or char[] or wchar[]. The result is
+ compared against each of the case expressions. If there is
+ a match, the corresponding case statement is transferred to.
+
+
+ The case expressions, ExpressionList, are a comma separated
+ list of expressions.
+
+
+ If none of the case expressions match, and there is a default
+ statement, the default statement is transferred to.
+
+
+ If none of the case expressions match, and there is not a default
+ statement, a SwitchError is thrown. The reason for this is
+ to catch the common programming error of adding a new value to
+ an enum, but failing to account for the extra value in
+ switch statements. This behavior is unlike C or C++.
+
+
+ The case expressions must all evaluate to a constant value
+ or array, and be implicitly convertible to the type T of the
+ switch Expression.
+
+
+ Case expressions must all evaluate to distinct values.
+ There may not be two or more default statements.
+
+
+ Case statements and default statements associated with the switch
+ can be nested within block statements; they do not have to be in
+ the outermost block. For example, this is allowed:
+
+
+
+ Like in C and C++, case statements 'fall through' to subsequent
+ case values. A break statement will exit the switch BlockStatement.
+ For example:
+
+
+
+ will set x to 4 if i is 1.
+
+
+ Note: Unlike C and C++, strings can be used in switch
+ expressions. For example:
+
+
+
+ For applications like command line switch processing, this
+ can lead to much more straightforward code, being clearer and
+ less error prone. Both ascii and wchar strings are allowed.
+
+
+ Implementation Note: The compiler's code generator may
+ assume that the case
+ statements are sorted by frequency of use, with the most frequent
+ appearing first and the least frequent last. Although this is
+ irrelevant as far as program correctness is concerned, it is of
+ performance interest.
+
+
+
+
+ continue executes the next iteration of its innermost enclosing
+ while, for, or do loop. The increment clause is executed.
+
+
+ If continue is followed by Identifier, the Identifier
+ must be the label of an enclosing while, for, or do
+ loop, and the next iteration of that loop is executed.
+ It is an error if
+ there is no such statement.
+
+
+ Any intervening finally clauses are executed, and any intervening
+ synchronization objects are released.
+
+
+ Note: If a finally clause executes a return, throw, or goto
+ out of the finally clause,
+ the continue target is never reached.
+
+
+
+ break exits the innermost enclosing while, for, do, or switch
+ statement, resuming execution at the statement following it.
+
+
+ If break is followed by Identifier, the Identifier
+ must be the label of an enclosing while, for, do or switch
+ statement, and that statement is exited. It is an error if
+ there is no such statement.
+
+
+ Any intervening finally clauses are executed, and any intervening
+ synchronization objects are released.
+
+
+ Note: If a finally clause executes a return, throw, or goto
+ out of the finally clause,
+ the break target is never reached.
+
+
+
+ Expression is required if the function specifies
+ a return type that is not void.
+ The Expression is implicitly converted to the
+ function return type.
+
+
+ At least one return statement is required if the function
+ specifies a return type that is not void.
+
+
+ Expression is allowed even if the function specifies
+ a void return type. The Expression will be evaluated,
+ but nothing will be returned.
+
+
+ Before the function actually returns, any enclosing finally
+ clauses are executed, and any enclosing synchronization
+ objects are released.
+
+
+ The function will not return if any enclosing finally clause
+ does a return, goto or throw that exits the finally clause.
+
+
+ If there is an out postcondition (see Contract Programming),
+ that postcondition is executed
+ after the Expression is evaluated and before the function
+ actually returns.
+
+
+
+ The second form, goto default;, transfers to the
+ innermost DefaultStatement of an enclosing SwitchStatement.
+
+
+ The third form, goto case;, transfers to the
+ next CaseStatement of the innermost enclosing
+ SwitchStatement.
+
+
+ The fourth form, goto case Expression;, transfers to the
+ CaseStatement of the innermost enclosing SwitchStatement
+ with a matching Expression.
+
+
+ Any intervening finally clauses are executed, along with
+ releasing any intervening synchronization mutexes.
+
+
+ It is illegal for a goto to be used to skip initializations.
+
+
+
+ where Expression evaluates to a class instance or struct
+ reference.
+ Within the with body the referenced object is searched first for
+ identifier symbols. The WithStatement
+
+
+
+ is semantically equivalent to:
+
+
+
+ Note that expression only gets evaluated once.
+ The with statement does not change what this or
+ super refer to.
+
+
+ For Symbol which is a scope or TemplateInstance,
+ the corresponding scope is searched when looking up symbols.
+ For example:
+
+
+
+
+
+ synchronized allows only one thread at a time to execute Statement.
+
+
+ synchronized (Expression), where Expression evaluates to an
+ Object reference, allows only one thread at a time to use
+ that Object to execute the Statement.
+ If Expression is an instance of an Interface, it is
+ cast to an Object.
+
+
+ The synchronization gets released even if Statement terminates
+ with an exception, goto, or return.
+
+
+ Example:
+
+
+
+ This implements a standard critical section.
+
+
+
+ Parameter declares a variable v of type T, where T is Object
+ or derived from Object. v is initialized by the throw expression if
+ T is of the same type or a base class of the throw expression.
+ The catch clause will be executed if the exception object is of
+ type T or derived from T.
+
+
+ If just type T is given and no variable v, then the catch clause
+ is still executed.
+
+
+ It is an error if any CatchParameter type T1 hides
+ a subsequent Catch with type T2, i.e. it is an error if
+ T1 is the same type as or a base class of T2.
+
+
+ LastCatch catches all exceptions.
+
+
+ The FinallyStatement is always executed, whether
+ the try BlockStatement exits with a goto, break,
+ continue, return, exception, or fall-through.
+
+
+ If an exception is raised in the FinallyStatement and
+ is not caught before the FinallyStatement is executed,
+ the new exception replaces any existing exception:
+
+
+
+ prints:
+
+
+ A FinallyStatement may not contain any Catches.
+ This restriction may be relaxed in future versions.
+
+
+
+ Expression is evaluated and must be an Object reference.
+ The Object reference is thrown as an exception.
+
+
+
+ Statement is evaluated.
+ Memory writes occurring before the Statement are
+ performed before any reads within or after the Statement.
+ Memory reads occurring after the Statement occur after
+ any writes before or within Statement are completed.
+
+
+ A volatile statement does not guarantee atomicity. For that,
+ use synchronized statements.
+
+
+
+ An asm statement enables the direct use of assembly language
+ instructions. This makes it easy to obtain direct access to special
+ CPU features without resorting to an external assembler. The
+ D compiler will take care of the function calling conventions,
+ stack setup, etc.
+
+
+ The format of the instructions is, of course, highly dependent
+ on the native instruction set of the target CPU, and so is
+ implementation defined.
+ But, the format will follow the following
+ conventions:
+
+
+
+ For example, for the Intel Pentium:
+
+
+
+ Inline assembler can be used to access hardware directly:
+
+
+
+ For some D implementations, such as a translator from D to C, an
+ inline assembler makes no sense, and need not be implemented.
+ The version statement can be used to account for this:
+
+
+
+
+
+
+ Example
+
+
+
+
+ That is the basic interface and will usually be all that you need to
+ understand. If it cannot unbox the object to the given type, it throws
+ UnboxException. As demonstrated, it uses implicit casts to behave in the
+ exact same way that static types behave. So for example, you can unbox
+ from int to real, but you cannot unbox from real to int: that would
+ require an explicit cast.
+
+
+ This therefore means that attempting to unbox an int as a string will
+ throw an error instead of formatting it. In general, you can call the
+ toString method on the box and receive a good result, depending upon
+ whether std.string.format accepts it.
+
+
+ Boxes can be compared to one another and they can be used as keys for
+ associative arrays.
+
+
+ There are also functions for converting to and from arrays of boxes.
+
+
+ Example
+
+
+ One use of this is to support a variadic function more easily and
+ robustly; simply call "boxArray(_arguments, _argptr)", then
+ do whatever you need to do with the array.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This will implicitly cast base types as necessary and in a way
+ consistent with static types - for example, it will cast a boxed byte
+ into int, but it won't cast a boxed float into short. If it cannot
+ cast, it throws UnboxException.
+
+
+ Example
+
+
+
+
+
+
+
+
-
- Template parameters can be types, values, or symbols.
- Types can be any type.
- Value parameters must be of an integral type, and
- specializations for them must resolve to an integral constant.
- Symbols can be any non-local symbol.
-
-
- Template parameter specializations
- constrain the values or types the TemplateParameter can
- accept.
-
-
- Template parameter defaults are the value or type to use for the
- TemplateParameter in case one is not supplied.
-
-
-
- If multiple templates with the same TemplateIdentifier are
- declared, they are distinct if they have a different number of
- arguments or are differently specialized.
-
-
- For example, a simple generic copy template would be:
-
-
-
- For example:
-
-
-
- For each template parameter, the following rules are applied in
- order until a type is deduced for each parameter:
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Template parameters can be types, values, or symbols.
+ Types can be any type.
+ Value parameters must be of an integral type, and
+ specializations for them must resolve to an integral constant.
+ Symbols can be any non-local symbol.
+
+
+ Template parameter specializations
+ constrain the values or types the TemplateParameter can
+ accept.
+
+
+ Template parameter defaults are the value or type to use for the
+ TemplateParameter in case one is not supplied.
+
+
+
+ A template instantiation can be aliased:
+
+
+
+ Multiple instantiations of a TemplateDeclaration with the same
+ TemplateParameterList all will refer to the same instantiation.
+ For example:
+
+
+ This is true even if the TemplateInstances are done in
+ different modules.
+
+
+ If multiple templates with the same TemplateIdentifier are
+ declared, they are distinct if they have a different number of
+ arguments or are differently specialized.
+
+
+ For example, a simple generic copy template would be:
+
+
+
+ To use the template, it must first be instantiated with a specific
+ type:
+
+
+
+
+
+
+ For example:
+
+
+
+ and:
+
+
+
+ TemplateParameter specializations and default
+ values are evaluated in the scope of the TemplateDeclaration.
+
+
+
+ For each template parameter, the following rules are applied in
+ order until a type is deduced for each parameter:
+
+
+
+ When considering matches, a class is
+ considered to be a match for any super classes or interfaces:
+
+
+
+
+
+
+
+
+ The template picked to instantiate is the one that is most specialized
+ that fits the types of the TemplateArgumentList.
+ Determine which is more specialized is done the same way as the
+ C++ partial ordering rules.
+ If the result is ambiguous, it is an error.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ then the semantic equivalent, called a ClassTemplateDeclaration
+ can be written as:
+
+
+
+
+
+
+
+ Templates cannot be declared inside functions.
+
+
+
-
- A typedef can be implicitly converted to its underlying
- type, but going the other way requires an explicit
- conversion. For example:
-
-
-
-
-
- If a typedef or enum has as a base type one of the types
- in the left column, it is converted to the type in the right
- column.
-
-
-
- Complex floating point types cannot be implicitly converted
- to non-complex floating point types.
-
-
- Imaginary floating point types cannot be implicitly converted to
- float, double, or real types. Float, double, or real types
- cannot be implicitly converted to imaginary floating
- point types.
-
-
-
- Delegates are declared similarly to function pointers,
- except that the keyword delegate takes the place
- of (*), and the identifier occurs afterwards:
-
-
-
- Delegates are called analogously to function pointers:
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A typedef can be implicitly converted to its underlying
+ type, but going the other way requires an explicit
+ conversion. For example:
+
+
+
+
+
+
+
+ If a typedef or enum has as a base type one of the types
+ in the left column, it is converted to the type in the right
+ column.
+
+
+
+ Complex floating point types cannot be implicitly converted
+ to non-complex floating point types.
+
+
+ Imaginary floating point types cannot be implicitly converted to
+ float, double, or real types. Float, double, or real types
+ cannot be implicitly converted to imaginary floating
+ point types.
+
+
+
+ Delegates are declared similarly to function pointers,
+ except that the keyword delegate takes the place
+ of (*), and the identifier occurs afterwards:
+
+
+
+ The C style syntax for declaring pointers to functions is
+ also supported:
+
+
+
+ A delegate is initialized analogously to function pointers:
+
+
+
+ Delegates cannot be initialized with static member functions
+ or non-member functions.
+
+
+ Delegates are called analogously to function pointers:
+
+
+
+
+
-
- It is inevitable that the D language will evolve over time.
- Therefore, the version identifier namespace beginning with "D_"
- is reserved for identifiers indicating D language specification
- or new feature conformance.
-
-
- Furthermore, predefined version identifiers from this list cannot
- be set from the command line or from version statements.
- (This prevents things like both Windows and linux
- being simultaneously set.)
-
-
- Compiler vendor specific versions can be predefined if the
- trademarked vendor
- identifier prefixes it, as in:
-
-
-
- VersionSpecifications and DebugSpecifications
- apply only to the module they appear in. The only global
- ones are the predefined ones and any that are specified on the
- command line.
-
-
- The version specification makes it straightforward to group
- a set of features under one major version, for example:
-
-
-
- debug(Integer) statements are compiled in when the debug
- level is >= Integer.
-
-
- debug(Identifier) statements are compiled in when the debug
- identifier matches Identifier.
-
-
- If Statement is a block statement, it does not
- introduce a new scope. For example:
-
-
-
-
-
- Version statements can nest.
-
-
- The optional else clause gets conditionally compiled in if the
- version predicate is false:
-
-
-
-
-
- For instance, there may be a full version as opposed to
- a demo version:
-
-
-
- Unlike AssertExpressions, StaticAsserts are always
- checked and evaluted by the compiler unless they appear in a
- false debug or version conditional.
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Any DeclarationBlock or Statement that is not
+ compiled in still must be syntactically correct.
+
+
+ No new scope is introduced, even if the
+ DeclarationBlock or Statement
+ is enclosed by { }.
+
+
+ ConditionalDeclarations and ConditionalStatements
+ can be nested.
+
+
+ The StaticAssert can be used
+ to issue errors at compilation time for branches of the conditional
+ compilation that are errors.
+
+ Condition comes in the following forms:
+
+
+
+
+
+ The version level and version identifier can
+ be set on the command line by the -version switch
+ or in the module itself with a VersionSpecification,
+ or they can be predefined by the compiler.
+
+
+ Version identifiers are in their own unique name space, they do
+ not conflict with debug identifiers or other symbols in the module.
+ Version identifiers defined in one module have no influence
+ over other imported modules.
+
+
+
+
+
+
+
+ Version identifiers or levels may not be forward referenced:
+
+
+
+ While the debug and version conditions superficially behave the same,
+ they are intended for very different purposes. Debug statements
+ are for adding debug code that is removed for the release version.
+ Version statements are to aid in portability and multiple release
+ versions.
+
+
+ Here's an example of a full version as opposed to
+ a demo version:
+
+
+
+ Various different version builds can be built with a parameter
+ to version:
+
+
+
+ These are presumably set by the command line as
+ -version=n and -version=identifier.
+
+
+
+
+
+ It is inevitable that the D language will evolve over time.
+ Therefore, the version identifier namespace beginning with "D_"
+ is reserved for identifiers indicating D language specification
+ or new feature conformance.
+
+
+ Furthermore, predefined version identifiers from this list cannot
+ be set from the command line or from version statements.
+ (This prevents things like both Windows and linux
+ being simultaneously set.)
+
+
+ Compiler vendor specific versions can be predefined if the
+ trademarked vendor
+ identifier prefixes it, as in:
+
+
+
+ It is important to use the right version identifier for the right
+ purpose. For example, use the vendor identifier when using a vendor
+ specific feature. Use the operating system identifier when using
+ an operating system specific feature, etc.
+
+
+
+
+
+ The debug ( Integer ) condition is satisfied
+ when the debug
+ level is >= Integer.
+
+
+ The debug ( Identifier ) condition is satisfied
+ when the debug identifier matches Identifier.
+
+
+
+
+
+
+
+ Debug specifications only affect the module they appear in, they
+ do not affect any imported modules. Debug identifiers are in their
+ own namespace, independent from version identifiers and other
+ symbols.
+
+
+ It is illegal to forward reference a debug specification:
+
+
+
+ Various different debug builds can be built with a parameter to debug:
+
+
+
+ These are presumably set by the command line as
+ -debug=n and -debug=identifier.
+
+
+
+ It is an error if AssignExpression cannot be implicitly converted
+ to a boolean type or if it cannot be evaluated at compile time.
+
+
+ StaticIfConditions cannot appear at module scope. They
+ can appear in class, template, struct, union, or function scope.
+ In function scope, the symbols referred to in the
+ AssignExpression can be any that can normally be referenced
+ by an expression at that point.
+ Otherwise, the only symbols that can be referred to are up one
+ scope level from the condition.
+
+
+
+ A StaticIfConditional condition differs from an
+ IfStatement in the following ways:
+
+
+
+
+
+
+
+ The way the type of Identifier is determined is analogous
+ to the way template parameter types are determined by
+ TemplateTypeParameterSpecialization.
+
+
+
+ Unlike AssertExpressions, StaticAsserts are always
+ checked and evaluted by the compiler unless they appear in an
+ unsatisfied conditional.
+
+
+
+ StaticAssert is useful tool for drawing attention to conditional
+ configurations not supported in the code.
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- Instead of the:
-
-
- For functions that in C would be __declspec(dllimport) or
- __declspec(dllexport), use the export attribute:
-
-
-
- These are required:
-
+
+ Instead of the:
+
+ of C, in D there is:
+
+
+
+
+
+ The Windows linkage attribute sets both the calling convention
+ and the name mangling scheme to be compatible with Windows.
+
+
+ For functions that in C would be __declspec(dllimport) or
+ __declspec(dllexport), use the export attribute:
+
+
+
+ If no function body is given, it's imported. If a function body
+ is given, it's exported.
+
+
+
+ These are required:
+
+
+ The myWinMain() function is where the user code goes, the
+ rest of WinMain is boilerplate to initialize and shut down
+ the D runtime system.
+
+
+
- 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
+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
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
+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
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
+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
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
+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
-
-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
+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
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
+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
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
+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
-
-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
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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
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
+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
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'
-
-
- Double quoted strings are enclosed by "". Escape sequences can be
- embedded into them with the typical \ notation.
- EndOfLine is regarded as a single \n character.
-
-
- "hello"
- "c:\\root\\foo.exe"
- "ab\n" string is 3 characters, 'a', 'b', and a linefeed
- "ab
- " string is 3 characters, 'a', 'b', and a linefeed
-
-
- Escape strings start with a \ and form an escape character sequence.
- Adjacent escape strings are concatenated:
-
-
- \n the linefeed character
- \t the tab character
- \" the double quote character
- \012 octal
- \x1A hex
- \u1234 wchar character
- \U00101234 dchar character
- \® ® dchar character
- \r\n carriage return, line feed
-
-
- Undefined escape sequences are errors.
-
- x"0A" same as "\x0A
- x"00 FBCD 32FD 0A" same as "\x00\xFB\xCD\x32\xFD\x0A"
-
-
- Whitespace and newlines are ignored, so the hex data can be
- easily formatted.
- The number of hex characters must be a multiple of 2.
-
- "hello " ~ "world" ~ \n // forms the string 'h','e','l','l','o',' ','w','o','r','l','d',linefeed
-
-
- The following are all equivalent:
-
-
- "ab" "c"
- r"ab" r"c"
- r"a" "bc"
- "a" ~ "b" ~ "c"
- \x61"bc"
-
-
-
-Character Literals
-
-
- CharacterLiteral:
- ' SingleQuotedCharacter '
-
- SingleQuotedCharacter
- Character
- EscapeSequence
-
-
- Character literals are a single character or escape sequence
- enclosed by single quotes, ' '.
-
-Integer Literals
-
-
- IntegerLiteral:
- Integer
- Integer IntegerSuffix
-
- Integer:
- Decimal
- Binary
- Octal
- Hexadecimal
- Integer _
-
- IntegerSuffix:
- l
- L
- u
- U
- lu
- Lu
- lU
- LU
- ul
- uL
- Ul
- UL
-
- Decimal:
- 0
- NonZeroDigit
- NonZeroDigit Decimal
- NonZeroDigit _ Decimal
-
- Binary:
- 0b BinaryDigits
- 0B BinaryDigits
-
- Octal:
- 0 OctalDigits
-
- Hexadecimal:
- 0x HexDigits
- 0X HexDigits
-
-
- Integers can be specified in decimal, binary, octal, or hexadecimal.
-
- 123_456 // 123456
- 1_2_3_4_5_6_ // 123456
-
-
- Integers can be immediately followed by one 'l' or one 'u' or both.
-
-
-
-
-
- Decimal Literal
- Type
-
- 0 .. 2147483647
- int
-
- 2147483648 .. 9223372036854775807
- long
-
- Decimal Literal, L Suffix
- Type
-
- 0L .. 9223372036854775807L
- long
-
- Decimal Literal, U Suffix
- Type
-
- 0U .. 4294967295U
- uint
-
- 4294967296U .. 18446744073709551615U
- ulong
-
- Decimal Literal, UL Suffix
- Type
-
- 0UL .. 18446744073709551615UL
- ulong
-
-
- Non-Decimal Literal
- Type
-
- 0x0 .. 0x7FFFFFFF
- int
-
- 0x80000000 .. 0xFFFFFFFF
- uint
-
- 0x100000000 .. 0x7FFFFFFFFFFFFFFF
- long
-
- 0x8000000000000000 .. 0xFFFFFFFFFFFFFFFF
- ulong
-
- Non-Decimal Literal, L Suffix
- Type
-
- 0x0L .. 0x7FFFFFFFFFFFFFFFL
- long
-
- 0x8000000000000000L .. 0xFFFFFFFFFFFFFFFFL
- ulong
-
- Non-Decimal Literal, U Suffix
- Type
-
- 0x0U .. 0xFFFFFFFFU
- uint
-
- 0x100000000UL .. 0xFFFFFFFFFFFFFFFFUL
- ulong
-
- Non-Decimal Literal, UL Suffix
- Type
-
- 0x0UL .. 0xFFFFFFFFFFFFFFFFUL
- ulong
-
- Floating Literals
-
-
- FloatLiteral:
- Float
- Float FloatSuffix
- Float ImaginarySuffix
- Float FloatSuffix ImaginarySuffix
-
- Float:
- DecimalFloat
- HexFloat
- Float _
-
- FloatSuffix:
- f
- F
- l
- L
-
- ImaginarySuffix:
- i
- I
-
-
- Floats can be in decimal or hexadecimal format,
- as in standard C.
-
- 123_456.567_8 // 123456.5678
- 1_2_3_4_5_6_._5_6_7_8 // 123456.5678
- 1_2_3_4_5_6_._5e-6_ // 123456.5e-6
-
-
- Floating literals with no suffix are of type double.
- Floats can be followed by one f, F, l
- or L suffix.
- The f or F suffix means it is a
- float, and l or L means it is a real.
-
- 0x1.FFFFFFFFFFFFFp1023 // double.max
- 0x1p-52 // double.epsilon
- 1.175494351e-38F // float.min
- 6.3i // idouble 6.3
- 6.3fi // ifloat 6.3
- 6.3LI // ireal 6.3
-
-
- It is an error if the literal exceeds the range of the type.
- It is not an error if the literal is rounded to fit into
- the significant digits of the type.
-
- 4.5 + 6.2i // complex number
-
-
-Keywords
-
- Keywords are reserved identifiers.
-
-
- Keyword:
- abstract
- alias
- align
- asm
- assert
- auto
-
- bit
- body
- break
- byte
-
- case
- cast
- catch
- cdouble
- cent
- cfloat
- char
- class
- const
- continue
- creal
-
- dchar
- debug
- default
- delegate
- delete
- deprecated
- do
- double
-
- else
- enum
- export
- extern
-
- false
- final
- finally
- float
- for
- foreach
- function
-
- goto
-
- idouble
- if
- ifloat
- import
- in
- inout
- int
- interface
- invariant
- ireal
- is
-
- long
-
- mixin
- module
-
- new
- null
-
- out
- override
-
- package
- pragma
- private
- protected
- public
-
- real
- return
-
- short
- static
- struct
- super
- switch
- synchronized
-
- template
- this
- throw
- true
- try
- typedef
- typeid
- typeof
-
- ubyte
- ucent
- uint
- ulong
- union
- unittest
- ushort
-
- version
- void
- volatile
-
- wchar
- while
- with
-
-
-Special Tokens
-
- These tokens are replaced with other tokens according to the following
- table:
-
-
-
- Special Token
- Replaced with...
-
- __FILE__
- string literal containing source file name
-
- __LINE__
- integer literal of the current source line number
-
- __DATE__
- string literal of the date of compilation "mmm dd yyyy"
-
- __TIME__
- string literal of the time of compilation "hh:mm:ss"
-
- __TIMESTAMP__
- string literal of the date and time of compilation "www mmm dd hh:mm:ss yyyy"
- Special Token Sequences
-
- Special token sequences are processed by the lexical analyzer, may
- appear between any other tokens, and do not affect the syntax
- parsing.
-
- SpecialTokenSequence
- # line Integer EndOfLine
- # line Integer Filespec EndOfLine
-
- Filespec
- " Characters "
-
-
- This sets the source line number to Integer,
- and optionally the source file name to Filespec,
- beginning with the next line of source text.
- The source file and line number is used for printing error messages
- and for mapping generated code back to the source for the symbolic
- debugging output.
-
- int #line 6 "foo\bar"
- x; // this is now line 6 of file foo\bar
-
-
- Note that the backslash character is not treated specially inside
- Filespec strings.
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
+Last update Thu May 19 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
+
End of Line
+
+
+
+
+ EndOfLine:
+ \u000D
+ \u000A
+ \u000D \u000A
+ EndOfFile
+
White Space
+
+
+
+
+ WhiteSpace:
+ Space
+ Space WhiteSpace
+
+ Space:
+ \u0020
+ \u0009
+ \u000B
+ \u000C
+ EndOfLine
+ Comment
+
Comments
+
+
+
+
+ Comment:
+ /* Characters */
+ // Characters EndOfLine
+ /+ Characters +/
+
+
+
+ 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
+
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
+
+ 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'
+
+
+ Double quoted strings are enclosed by "". Escape sequences can be
+ embedded into them with the typical \ notation.
+ EndOfLine is regarded as a single \n character.
+
+
+ "hello"
+ "c:\\root\\foo.exe"
+ "ab\n" string is 3 characters, 'a', 'b', and a linefeed
+ "ab
+ " string is 3 characters, 'a', 'b', and a linefeed
+
+
+ Escape strings start with a \ and form an escape character sequence.
+ Adjacent escape strings are concatenated:
+
+
+ \n the linefeed character
+ \t the tab character
+ \" the double quote character
+ \012 octal
+ \x1A hex
+ \u1234 wchar character
+ \U00101234 dchar character
+ \® ® dchar character
+ \r\n carriage return, line feed
+
+
+ Undefined escape sequences are errors.
+
+ x"0A" same as "\x0A
+ x"00 FBCD 32FD 0A" same as "\x00\xFB\xCD\x32\xFD\x0A"
+
+
+ Whitespace and newlines are ignored, so the hex data can be
+ easily formatted.
+ The number of hex characters must be a multiple of 2.
+
+ "hello " ~ "world" ~ \n // forms the string 'h','e','l','l','o',' ','w','o','r','l','d',linefeed
+
+
+ The following are all equivalent:
+
+
+ "ab" "c"
+ r"ab" r"c"
+ r"a" "bc"
+ "a" ~ "b" ~ "c"
+ \x61"bc"
+
+
+
+Character Literals
+
+
+
+
+ CharacterLiteral:
+ ' SingleQuotedCharacter '
+
+ SingleQuotedCharacter
+ Character
+ EscapeSequence
+
Integer Literals
+
+
+
+
+ IntegerLiteral:
+ Integer
+ Integer IntegerSuffix
+
+ Integer:
+ Decimal
+ Binary
+ Octal
+ Hexadecimal
+ Integer _
+
+ IntegerSuffix:
+ l
+ L
+ u
+ U
+ lu
+ Lu
+ lU
+ LU
+ ul
+ uL
+ Ul
+ UL
+
+ Decimal:
+ 0
+ NonZeroDigit
+ NonZeroDigit Decimal
+ NonZeroDigit _ Decimal
+
+ Binary:
+ 0b BinaryDigits
+ 0B BinaryDigits
+
+ Octal:
+ 0 OctalDigits
+
+ Hexadecimal:
+ 0x HexDigits
+ 0X HexDigits
+
+ 123_456 // 123456
+ 1_2_3_4_5_6_ // 123456
+
+
+ Integers can be immediately followed by one 'l' or one 'u' or both.
+
+
+
+
+
+ Decimal Literal
+ Type
+
+ 0 .. 2147483647
+ int
+
+ 2147483648 .. 9223372036854775807
+ long
+
+ Decimal Literal, L Suffix
+ Type
+
+ 0L .. 9223372036854775807L
+ long
+
+ Decimal Literal, U Suffix
+ Type
+
+ 0U .. 4294967295U
+ uint
+
+ 4294967296U .. 18446744073709551615U
+ ulong
+
+ Decimal Literal, UL Suffix
+ Type
+
+ 0UL .. 18446744073709551615UL
+ ulong
+
+
+ Non-Decimal Literal
+ Type
+
+ 0x0 .. 0x7FFFFFFF
+ int
+
+ 0x80000000 .. 0xFFFFFFFF
+ uint
+
+ 0x100000000 .. 0x7FFFFFFFFFFFFFFF
+ long
+
+ 0x8000000000000000 .. 0xFFFFFFFFFFFFFFFF
+ ulong
+
+ Non-Decimal Literal, L Suffix
+ Type
+
+ 0x0L .. 0x7FFFFFFFFFFFFFFFL
+ long
+
+ 0x8000000000000000L .. 0xFFFFFFFFFFFFFFFFL
+ ulong
+
+ Non-Decimal Literal, U Suffix
+ Type
+
+ 0x0U .. 0xFFFFFFFFU
+ uint
+
+ 0x100000000UL .. 0xFFFFFFFFFFFFFFFFUL
+ ulong
+
+ Non-Decimal Literal, UL Suffix
+ Type
+
+ 0x0UL .. 0xFFFFFFFFFFFFFFFFUL
+ ulong
+
+ Floating Literals
+
+
+
+
+ FloatLiteral:
+ Float
+ Float FloatSuffix
+ Float ImaginarySuffix
+ Float FloatSuffix ImaginarySuffix
+
+ Float:
+ DecimalFloat
+ HexFloat
+ Float _
+
+ FloatSuffix:
+ f
+ F
+ l
+ L
+
+ ImaginarySuffix:
+ i
+ I
+
+ 123_456.567_8 // 123456.5678
+ 1_2_3_4_5_6_._5_6_7_8 // 123456.5678
+ 1_2_3_4_5_6_._5e-6_ // 123456.5e-6
+
+
+ Floating literals with no suffix are of type double.
+ Floats can be followed by one f, F, l
+ or L suffix.
+ The f or F suffix means it is a
+ float, and l or L means it is a real.
+
+ 0x1.FFFFFFFFFFFFFp1023 // double.max
+ 0x1p-52 // double.epsilon
+ 1.175494351e-38F // float.min
+ 6.3i // idouble 6.3
+ 6.3fi // ifloat 6.3
+ 6.3LI // ireal 6.3
+
+
+ It is an error if the literal exceeds the range of the type.
+ It is not an error if the literal is rounded to fit into
+ the significant digits of the type.
+
+ 4.5 + 6.2i // complex number
+
+
+Keywords
+
+ Keywords are reserved identifiers.
+
+
+
+
+ Keyword:
+ abstract
+ alias
+ align
+ asm
+ assert
+ auto
+
+ bit
+ body
+ break
+ byte
+
+ case
+ cast
+ catch
+ cdouble
+ cent
+ cfloat
+ char
+ class
+ const
+ continue
+ creal
+
+ dchar
+ debug
+ default
+ delegate
+ delete
+ deprecated
+ do
+ double
+
+ else
+ enum
+ export
+ extern
+
+ false
+ final
+ finally
+ float
+ for
+ foreach
+ function
+
+ goto
+
+ idouble
+ if
+ ifloat
+ import
+ in
+ inout
+ int
+ interface
+ invariant
+ ireal
+ is
+
+ long
+
+ mixin
+ module
+
+ new
+ null
+
+ out
+ override
+
+ package
+ pragma
+ private
+ protected
+ public
+
+ real
+ return
+
+ short
+ static
+ struct
+ super
+ switch
+ synchronized
+
+ template
+ this
+ throw
+ true
+ try
+ typedef
+ typeid
+ typeof
+
+ ubyte
+ ucent
+ uint
+ ulong
+ union
+ unittest
+ ushort
+
+ version
+ void
+ volatile
+
+ wchar
+ while
+ with
+
Special Tokens
+
+ These tokens are replaced with other tokens according to the following
+ table:
+
+
+
+ Special Token
+ Replaced with...
+
+ __FILE__
+ string literal containing source file name
+
+ __LINE__
+ integer literal of the current source line number
+
+ __DATE__
+ string literal of the date of compilation "mmm dd yyyy"
+
+ __TIME__
+ string literal of the time of compilation "hh:mm:ss"
+
+ __TIMESTAMP__
+ string literal of the date and time of compilation "www mmm dd hh:mm:ss yyyy"
+ Special Token Sequences
+
+ Special token sequences are processed by the lexical analyzer, may
+ appear between any other tokens, and do not affect the syntax
+ parsing.
+
+
+
+ SpecialTokenSequence
+ # line Integer EndOfLine
+ # line Integer Filespec EndOfLine
+
+ Filespec
+ " Characters "
+
+
+
+ int #line 6 "foo\bar"
+ x; // this is now line 6 of file foo\bar
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-
-Memory Management
-
- Any non-trivial program needs to allocate and free memory.
- Memory management techniques become more and more important as
- programs increase in complexity, size, and performance.
- D offers many options for managing memory.
-
-
-
- This chapter describes techniques for using them, as well
- as some advanced alternatives:
-
-
-
-
-Strings (and Array) Copy-on-Write
-
- Consider the case of passing an array to a function, possibly
- modifying the contents of the array, and returning the modified
- array. Since arrays are passed by reference, not by value,
- a crucial issue is who owns the contents of the array?
- For example, a function to convert an array of characters to
- upper case:
-
-
- char[] toupper(char[] s)
- {
- int i;
-
- for (i = 0; i < s.length; i++)
- {
- char c = s[i];
- if ('a' <= c && c <= 'z')
- s[i] = c - (cast(char)'a' - 'A');
- }
- return s;
- }
-
-
- Note that the caller's version of s[] is also modified. This may
- be not at all what was intended, or worse, s[] may be a slice
- into a read-only section of memory.
-
- char[] toupper(char[] s)
- {
- int changed;
- int i;
-
- changed = 0;
- for (i = 0; i < s.length; i++)
- {
- char c = s[i];
- if ('a' <= c && c <= 'z')
- {
- if (!changed)
- { char[] r = new char[s.length];
- r[] = s;
- s = r;
- changed = 1;
- }
- s[i] = c - (cast(char)'a' - 'A');
- }
- }
- return s;
- }
-
-
- Copy-on-write is the protocol implemented by array processing
- functions in the D Phobos runtime library.
-
-Real Time
-
- Real time programming means that a program must be able to
- guarantee a maximum latency, or time to complete an operation.
- With most memory allocation schemes, including malloc/free and
- garbage collection, the latency is theoretically not bound.
- The most reliable way to guarantee latency is to preallocate
- all data that will be needed by the time critical portion.
- If no calls to allocate memory are done, the gc will not run
- and so will not cause the maximum latency to be exceeded.
-
-Smooth Operation
-
- Related to real time programming is the need for a program to
- operate smoothly, without arbitrary pauses while the garbage
- collector stops everything to run a collection.
- An example of such a program would be an interactive shooter
- type game. Having the game play pause erratically, while not
- fatal to the program, can be annoying to the user.
-
- There are several techniques to eliminate or mitigate the effect:
-
- Free Lists
-
- Free lists are a great way to accelerate access to a frequently
- allocated and discarded type. The idea is simple - instead of
- deallocating an object when done with it, put it on a free list.
- When allocating, pull one off the free list first.
-
-
- class Foo
- {
- static Foo freelist; // start of free list
-
- static Foo allocate()
- { Foo f;
-
- if (freelist)
- { f = freelist;
- freelist = f.next;
- }
- else
- f = new Foo();
- return f;
- }
-
- static void deallocate(Foo f)
- {
- f.next = freelist;
- freelist = f;
- }
-
- Foo next; // for use by FooFreeList
- ...
- }
-
- void test()
- {
- Foo f = Foo.allocate();
- ...
- Foo.deallocate(f);
- }
-
-
- Such free list approaches can be very high performance.
-
-
-
-
-Reference Counting
-
- The idea behind reference counting is to include a count
- field in the object. Increment it for each additional reference
- to it, and decrement it whenever a reference to it ceases.
- When the count hits 0, the object can be deleted.
- Explicit Class Instance Allocation
-
- D provides a means of creating custom allocators and deallocators
- for class instances. Normally, these would be allocated on the
- garbage collected heap, and deallocated when the collector decides
- to run. For specialized purposes, this can be handled by
- creating NewDeclarations and DeleteDeclarations.
- For example, to allocate using the C runtime library's
- malloc and free:
-
-
- import std.c.stdlib;
- import std.outofmemory;
- import std.gc;
-
- class Foo
- {
- new(uint sz)
- {
- void* p;
-
- p = std.c.stdlib.malloc(sz);
- if (!p)
- throw new OutOfMemory();
- gc.addRange(p, p + sz);
- return p;
- }
-
- delete(void* p)
- {
- if (p)
- { gc.removeRange(p);
- std.c.stdlib.free(p);
- }
- }
- }
-
-
- The critical features of new() are:
-
-
-
-
- The critical features of delete() are:
-
-
-
-
- If memory is allocated using class specific allocators and deallocators,
- careful coding practices must be followed to avoid memory leaks
- and dangling references. In the presence of exceptions, it is
- particularly important to practice RAII to prevent memory leaks.
-
-Mark/Release
-
- Mark/Release is equivalent to a stack method of allocating and
- freeing memory. A 'stack' is created in memory. Objects are allocated
- by simply moving a pointer down the stack. Various points are
- 'marked', and then whole sections of memory are released
- simply by resetting the stack pointer back to a marked point.
-
-
- import std.c.stdlib;
- import std.outofmemory;
-
- class Foo
- {
- static void[] buffer;
- static int bufindex;
- static const int bufsize = 100;
-
- static this()
- { void *p;
-
- p = malloc(bufsize);
- if (!p)
- throw new OutOfMemory;
- gc.addRange(p, p + bufsize);
- buffer = p[0 .. bufsize];
- }
-
- static ~this()
- {
- if (buffer.length)
- {
- gc.removeRange(buffer);
- free(buffer);
- buffer = null;
- }
- }
-
- new(uint sz)
- { void *p;
-
- p = &buffer[bufindex];
- bufindex += sz;
- if (bufindex > buffer.length)
- throw new OutOfMemory;
- return p;
- }
-
- delete(void* p)
- {
- assert(0);
- }
-
- static int mark()
- {
- return bufindex;
- }
-
- static void release(int i)
- {
- bufindex = i;
- }
- }
-
- void test()
- {
- int m = Foo.mark();
- Foo f1 = new Foo; // allocate
- Foo f2 = new Foo; // allocate
- ...
- Foo.release(m); // deallocate f1 and f2
- }
-
-
- RAII (Resource Acquisition Is Initialization)
-
- RAII techniques can be useful in avoiding memory leaks
- when using explicit allocators and deallocators.
- Adding the auto attribute
- to such classes can help.
-
-Allocating Class Instances On The Stack
-
- Allocating class instances on the stack is useful for temporary
- objects that are to be automatically deallocated when the function
- is exited. No special handling is needed to account for
- function termination via stack unwinding from an exception.
- To work, they must not have destructors, since such a destructor
- would never get called.
-
- import std.c.stdlib;
-
- class Foo
- {
- new(uint sz, void *p)
- {
- return p;
- }
-
- delete(void* p)
- {
- assert(0);
- }
- }
-
- void test()
- {
- Foo f = new(std.c.stdlib.alloca(Foo.classinfo.init.length)) Foo;
- ...
- }
-
-
-
-
-
-Allocating Uninitialized Arrays On The Stack
-
- Arrays are always initialized in D. So, the following declaration:
-
-
- void foo()
- { byte[1024] buffer;
-
- fillBuffer(buffer);
- ...
- }
-
-
- will not be as fast as it might be since the buffer[] contents
- are always initialized. If careful profiling of the program shows
- that this initialization is a speed problem, it can be eliminated using
- the following idiom:
-
-
- import std.c.stdlib;
-
- void foo()
- { byte[] buffer = (cast(byte*)std.c.stdlib.alloca(1024))[0 .. 1024];
-
- fillBuffer(buffer);
- ...
- }
-
-
- A good D implementation will recognize that alloca() is called with
- a constant size argument, and so can be replaced with an uninitialized
- array of the same size allocated on the stack. This will produce
- execution performance equivalent to using an uninitialized stack
- array in C.
-
-
-
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright (c) 1999-2004 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+
+Memory Management
+
+ Any non-trivial program needs to allocate and free memory.
+ Memory management techniques become more and more important as
+ programs increase in complexity, size, and performance.
+ D offers many options for managing memory.
+
+
+
+ This chapter describes techniques for using them, as well
+ as some advanced alternatives:
+
+
+
+
+Strings (and Array) Copy-on-Write
+
+ Consider the case of passing an array to a function, possibly
+ modifying the contents of the array, and returning the modified
+ array. Since arrays are passed by reference, not by value,
+ a crucial issue is who owns the contents of the array?
+ For example, a function to convert an array of characters to
+ upper case:
+
+
+
+
+ char[] toupper(char[] s)
+ {
+ int i;
+
+ for (i = 0; i < s.length; i++)
+ {
+ char c = s[i];
+ if ('a' <= c && c <= 'z')
+ s[i] = c - (cast(char)'a' - 'A');
+ }
+ return s;
+ }
+
+
+
+ char[] toupper(char[] s)
+ {
+ int changed;
+ int i;
+
+ changed = 0;
+ for (i = 0; i < s.length; i++)
+ {
+ char c = s[i];
+ if ('a' <= c && c <= 'z')
+ {
+ if (!changed)
+ { char[] r = new char[s.length];
+ r[] = s;
+ s = r;
+ changed = 1;
+ }
+ s[i] = c - (cast(char)'a' - 'A');
+ }
+ }
+ return s;
+ }
+
Real Time
+
+ Real time programming means that a program must be able to
+ guarantee a maximum latency, or time to complete an operation.
+ With most memory allocation schemes, including malloc/free and
+ garbage collection, the latency is theoretically not bound.
+ The most reliable way to guarantee latency is to preallocate
+ all data that will be needed by the time critical portion.
+ If no calls to allocate memory are done, the gc will not run
+ and so will not cause the maximum latency to be exceeded.
+
+Smooth Operation
+
+ Related to real time programming is the need for a program to
+ operate smoothly, without arbitrary pauses while the garbage
+ collector stops everything to run a collection.
+ An example of such a program would be an interactive shooter
+ type game. Having the game play pause erratically, while not
+ fatal to the program, can be annoying to the user.
+
+ There are several techniques to eliminate or mitigate the effect:
+
+ Free Lists
+
+ Free lists are a great way to accelerate access to a frequently
+ allocated and discarded type. The idea is simple - instead of
+ deallocating an object when done with it, put it on a free list.
+ When allocating, pull one off the free list first.
+
+
+
+
+ class Foo
+ {
+ static Foo freelist; // start of free list
+
+ static Foo allocate()
+ { Foo f;
+
+ if (freelist)
+ { f = freelist;
+ freelist = f.next;
+ }
+ else
+ f = new Foo();
+ return f;
+ }
+
+ static void deallocate(Foo f)
+ {
+ f.next = freelist;
+ freelist = f;
+ }
+
+ Foo next; // for use by FooFreeList
+ ...
+ }
+
+ void test()
+ {
+ Foo f = Foo.allocate();
+ ...
+ Foo.deallocate(f);
+ }
+
+
+
+Reference Counting
+
+ The idea behind reference counting is to include a count
+ field in the object. Increment it for each additional reference
+ to it, and decrement it whenever a reference to it ceases.
+ When the count hits 0, the object can be deleted.
+ Explicit Class Instance Allocation
+
+ D provides a means of creating custom allocators and deallocators
+ for class instances. Normally, these would be allocated on the
+ garbage collected heap, and deallocated when the collector decides
+ to run. For specialized purposes, this can be handled by
+ creating NewDeclarations and DeleteDeclarations.
+ For example, to allocate using the C runtime library's
+ malloc and free:
+
+
+
+
+ import std.c.stdlib;
+ import std.outofmemory;
+ import std.gc;
+
+ class Foo
+ {
+ new(uint sz)
+ {
+ void* p;
+
+ p = std.c.stdlib.malloc(sz);
+ if (!p)
+ throw new OutOfMemory();
+ gc.addRange(p, p + sz);
+ return p;
+ }
+
+ delete(void* p)
+ {
+ if (p)
+ { gc.removeRange(p);
+ std.c.stdlib.free(p);
+ }
+ }
+ }
+
+
+
+ The critical features of delete() are:
+
+
+
+
+ If memory is allocated using class specific allocators and deallocators,
+ careful coding practices must be followed to avoid memory leaks
+ and dangling references. In the presence of exceptions, it is
+ particularly important to practice RAII to prevent memory leaks.
+
+Mark/Release
+
+ Mark/Release is equivalent to a stack method of allocating and
+ freeing memory. A 'stack' is created in memory. Objects are allocated
+ by simply moving a pointer down the stack. Various points are
+ 'marked', and then whole sections of memory are released
+ simply by resetting the stack pointer back to a marked point.
+
+
+
+
+ import std.c.stdlib;
+ import std.outofmemory;
+
+ class Foo
+ {
+ static void[] buffer;
+ static int bufindex;
+ static const int bufsize = 100;
+
+ static this()
+ { void *p;
+
+ p = malloc(bufsize);
+ if (!p)
+ throw new OutOfMemory;
+ gc.addRange(p, p + bufsize);
+ buffer = p[0 .. bufsize];
+ }
+
+ static ~this()
+ {
+ if (buffer.length)
+ {
+ gc.removeRange(buffer);
+ free(buffer);
+ buffer = null;
+ }
+ }
+
+ new(uint sz)
+ { void *p;
+
+ p = &buffer[bufindex];
+ bufindex += sz;
+ if (bufindex > buffer.length)
+ throw new OutOfMemory;
+ return p;
+ }
+
+ delete(void* p)
+ {
+ assert(0);
+ }
+
+ static int mark()
+ {
+ return bufindex;
+ }
+
+ static void release(int i)
+ {
+ bufindex = i;
+ }
+ }
+
+ void test()
+ {
+ int m = Foo.mark();
+ Foo f1 = new Foo; // allocate
+ Foo f2 = new Foo; // allocate
+ ...
+ Foo.release(m); // deallocate f1 and f2
+ }
+
RAII (Resource Acquisition Is Initialization)
+
+ RAII techniques can be useful in avoiding memory leaks
+ when using explicit allocators and deallocators.
+ Adding the auto attribute
+ to such classes can help.
+
+Allocating Class Instances On The Stack
+
+ Allocating class instances on the stack is useful for temporary
+ objects that are to be automatically deallocated when the function
+ is exited. No special handling is needed to account for
+ function termination via stack unwinding from an exception.
+ To work, they must not have destructors, since such a destructor
+ would never get called.
+
+
+
+ import std.c.stdlib;
+
+ class Foo
+ {
+ new(uint sz, void *p)
+ {
+ return p;
+ }
+
+ delete(void* p)
+ {
+ assert(0);
+ }
+ }
+
+ void test()
+ {
+ Foo f = new(std.c.stdlib.alloca(Foo.classinfo.init.length)) Foo;
+ ...
+ }
+
+
+
+Allocating Uninitialized Arrays On The Stack
+
+ Arrays are always initialized in D. So, the following declaration:
+
+
+
+
+ void foo()
+ { byte[1024] buffer;
+
+ fillBuffer(buffer);
+ ...
+ }
+
+
+
+ import std.c.stdlib;
+
+ void foo()
+ { byte[] buffer = (cast(byte*)std.c.stdlib.alloca(1024))[0 .. 1024];
+
+ fillBuffer(buffer);
+ ...
+ }
+
+
+
+
+Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last modified May 16, 2004.
-
-
-Mixins
-
- Mixins mean different things in different programming languages.
- In D, a mixin takes an arbitrary set of declarations from
- the body of a TemplateDeclaration and inserts them
- into the current context.
-
-
- TemplateMixin:
- mixin TemplateIdentifier ;
- mixin TemplateIdentifier MixinIdentifier ;
- mixin TemplateIdentifier !( TemplateArgumentList ) ;
- mixin TemplateIdentifier !( TemplateArgumentList ) MixinIdentifier ;
-
- MixinIdentifier:
- Identifier
-
-
- A TemplateMixin can occur in declaration lists of modules,
- classes, structs, unions, and as a statement.
- The TemplateIdentifier refers to a TemplateDeclaration.
- If the TemplateDeclaration has no parameters, the mixin
- form that has no !(TemplateArgumentList)
- can be used.
-
- template Foo()
- {
- int x = 5;
- }
-
- mixin Foo;
-
- struct Bar
- {
- mixin Foo;
- }
-
- void test()
- {
- printf("x = %d\n", x); // prints 5
- { Bar b;
- int x = 3;
-
- printf("b.x = %d\n", b.x); // prints 5
- printf("x = %d\n", x); // prints 3
- {
- mixin Foo;
- printf("x = %d\n", x); // prints 5
- x = 4;
- printf("x = %d\n", x); // prints 4
- }
- printf("x = %d\n", x); // prints 3
- }
- printf("x = %d\n", x); // prints 5
- }
-
-
- Mixins can be parameterized:
-
-
- template Foo(T)
- {
- T x = 5;
- }
-
- mixin Foo!(int); // create x of type int
-
-
- Mixins can add virtual functions to a class:
-
-
- template Foo()
- {
- void func() { printf("Foo.func()\n"); }
- }
-
- class Bar
- {
- mixin Foo;
- }
-
- class Code : Bar
- {
- void func() { printf("Code.func()\n"); }
- }
-
- void test()
- {
- Bar b = new Bar();
- b.func(); // calls Foo.func()
-
- b = new Code();
- b.func(); // calls Code.func()
- }
-
-
- Mixins are evaluted in the scope of where they appear, not the scope
- of the template declaration:
-
-
- int y = 3;
-
- template Foo()
- {
- int abc() { return y; }
- }
-
- void test()
- {
- int y = 8;
- mixin Foo; // local y is picked up, not global y
- assert(abc() == 8);
- }
-
-
- Mixins can parameterize symbols using alias parameters:
-
-
- template Foo(alias b)
- {
- int abc() { return b; }
- }
-
- void test()
- {
- int y = 8;
- mixin Foo!(y);
- assert(abc() == 8);
- }
-
-
- This example uses a mixin to implement a generic Duff's device
- for an arbitrary statement (in this case, the arbitrary statement
- is in bold). A nested function is generated as well as a
- delegate literal, these can be inlined by the compiler:
-
-
- template duffs_device(alias id1, alias id2, alias s)
- {
- void duff_loop()
- {
- if (id1 < id2)
- {
- typeof(id1) n = (id2 - id1 + 7) / 8;
- switch ((id2 - id1) % 8)
- {
- case 0: do { s();
- case 7: s();
- case 6: s();
- case 5: s();
- case 4: s();
- case 3: s();
- case 2: s();
- case 1: s();
- } while (--n > 0);
- }
- }
- }
- }
-
- void foo() { printf("foo\n"); }
-
- void test()
- {
- int i = 1;
- int j = 11;
-
- mixin duffs_device!(i, j, delegate { foo(); } );
- duff_loop(); // executes foo() 10 times
- }
-
-
-Mixin Scope
-
- The declarations in a mixin are 'imported' into the surrounding
- scope. If the name of a declaration in a mixin is the same
- as a declaration in the surrounding scope, the surrounding declaration
- overrides the mixin one:
-
-
- int x = 3;
-
- template Foo()
- {
- int x = 5;
- int y = 5;
- }
-
- mixin Foo;
- int y = 3;
-
- void test()
- {
- printf("x = %d\n", x); // prints 3
- printf("y = %d\n", y); // prints 3
- }
-
-
- If two different mixins are put in the same scope, and each
- define a declaration with the same name, there is an ambiguity
- error when the declaration is referenced:
-
-
- template Foo()
- {
- int x = 5;
- }
-
- template Bar()
- {
- int x = 4;
- }
-
- mixin Foo;
- mixin Bar;
-
- void test()
- {
- printf("x = %d\n", x); // error, x is ambiguous
- }
-
-
- If a mixin has a MixinIdentifier, it can be used to
- disambiguate:
-
-
- int x = 6;
-
- template Foo()
- {
- int x = 5;
- int y = 7;
- }
-
- template Bar()
- {
- int x = 4;
- }
-
- mixin Foo F;
- mixin Bar B;
-
- void test()
- {
- printf("y = %d\n", y); // prints 7
- printf("x = %d\n", x); // prints 6
- printf("F.x = %d\n", F.x); // prints 5
- printf("B.x = %d\n", B.x); // prints 4
- }
-
-
- A mixin has its own scope, even if a declaration is overridden
- by the enclosing one:
-
-
- int x = 4;
-
- template Foo()
- {
- int x = 5;
- int bar() { return x; }
- }
-
- mixin Foo;
-
- void test()
- {
- printf("x = %d\n", x); // prints 4
- printf("bar() = %d\n", bar()); // prints 5
- }
-
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright (c) 2004 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+
+Mixins
+
+ Mixins mean different things in different programming languages.
+ In D, a mixin takes an arbitrary set of declarations from
+ the body of a TemplateDeclaration and inserts them
+ into the current context.
+
+
+ TemplateMixin:
+ mixin TemplateIdentifier ;
+ mixin TemplateIdentifier MixinIdentifier ;
+ mixin TemplateIdentifier !( TemplateArgumentList ) ;
+ mixin TemplateIdentifier !( TemplateArgumentList ) MixinIdentifier ;
+
+ MixinIdentifier:
+ Identifier
+
+
+ A TemplateMixin can occur in declaration lists of modules,
+ classes, structs, unions, and as a statement.
+ The TemplateIdentifier refers to a TemplateDeclaration.
+ If the TemplateDeclaration has no parameters, the mixin
+ form that has no !(TemplateArgumentList)
+ can be used.
+
+
+
+ template Foo()
+ {
+ int x = 5;
+ }
+
+ mixin Foo;
+
+ struct Bar
+ {
+ mixin Foo;
+ }
+
+ void test()
+ {
+ printf("x = %d\n", x); // prints 5
+ { Bar b;
+ int x = 3;
+
+ printf("b.x = %d\n", b.x); // prints 5
+ printf("x = %d\n", x); // prints 3
+ {
+ mixin Foo;
+ printf("x = %d\n", x); // prints 5
+ x = 4;
+ printf("x = %d\n", x); // prints 4
+ }
+ printf("x = %d\n", x); // prints 3
+ }
+ printf("x = %d\n", x); // prints 5
+ }
+
+
+
+ template Foo(T)
+ {
+ T x = 5;
+ }
+
+ mixin Foo!(int); // create x of type int
+
+
+
+ template Foo()
+ {
+ void func() { printf("Foo.func()\n"); }
+ }
+
+ class Bar
+ {
+ mixin Foo;
+ }
+
+ class Code : Bar
+ {
+ void func() { printf("Code.func()\n"); }
+ }
+
+ void test()
+ {
+ Bar b = new Bar();
+ b.func(); // calls Foo.func()
+
+ b = new Code();
+ b.func(); // calls Code.func()
+ }
+
+
+
+ int y = 3;
+
+ template Foo()
+ {
+ int abc() { return y; }
+ }
+
+ void test()
+ {
+ int y = 8;
+ mixin Foo; // local y is picked up, not global y
+ assert(abc() == 8);
+ }
+
+
+
+ template Foo(alias b)
+ {
+ int abc() { return b; }
+ }
+
+ void test()
+ {
+ int y = 8;
+ mixin Foo!(y);
+ assert(abc() == 8);
+ }
+
+
+
+ template duffs_device(alias id1, alias id2, alias s)
+ {
+ void duff_loop()
+ {
+ if (id1 < id2)
+ {
+ typeof(id1) n = (id2 - id1 + 7) / 8;
+ switch ((id2 - id1) % 8)
+ {
+ case 0: do { s();
+ case 7: s();
+ case 6: s();
+ case 5: s();
+ case 4: s();
+ case 3: s();
+ case 2: s();
+ case 1: s();
+ } while (--n > 0);
+ }
+ }
+ }
+ }
+
+ void foo() { printf("foo\n"); }
+
+ void test()
+ {
+ int i = 1;
+ int j = 11;
+
+ mixin duffs_device!(i, j, delegate { foo(); } );
+ duff_loop(); // executes foo() 10 times
+ }
+
Mixin Scope
+
+ The declarations in a mixin are 'imported' into the surrounding
+ scope. If the name of a declaration in a mixin is the same
+ as a declaration in the surrounding scope, the surrounding declaration
+ overrides the mixin one:
+
+
+
+
+ int x = 3;
+
+ template Foo()
+ {
+ int x = 5;
+ int y = 5;
+ }
+
+ mixin Foo;
+ int y = 3;
+
+ void test()
+ {
+ printf("x = %d\n", x); // prints 3
+ printf("y = %d\n", y); // prints 3
+ }
+
+
+
+ template Foo()
+ {
+ int x = 5;
+ }
+
+ template Bar()
+ {
+ int x = 4;
+ }
+
+ mixin Foo;
+ mixin Bar;
+
+ void test()
+ {
+ printf("x = %d\n", x); // error, x is ambiguous
+ }
+
+
+
+ int x = 6;
+
+ template Foo()
+ {
+ int x = 5;
+ int y = 7;
+ }
+
+ template Bar()
+ {
+ int x = 4;
+ }
+
+ mixin Foo F;
+ mixin Bar B;
+
+ void test()
+ {
+ printf("y = %d\n", y); // prints 7
+ printf("x = %d\n", x); // prints 6
+ printf("F.x = %d\n", F.x); // prints 5
+ printf("B.x = %d\n", B.x); // prints 4
+ }
+
+
+
+ int x = 4;
+
+ template Foo()
+ {
+ int x = 5;
+ int bar() { return x; }
+ }
+
+ mixin Foo;
+
+ void test()
+ {
+ printf("x = %d\n", x); // prints 4
+ printf("bar() = %d\n", bar()); // prints 5
+ }
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last update Mar 10, 2004
-
-
-Modules
-
-
- Module:
- ModuleDeclaration DeclDefs
- DeclDefs
-
- DeclDefs:
- DeclDef
- DeclDef DeclDefs
-
- DeclDef:
- AttributeSpecifier
- ImportDeclaration
- EnumDeclaration
- ClassDeclaration
- InterfaceDeclaration
- AggregateDeclaration
- Declaration
- Constructor
- Destructor
- Invariant
- Unittest
- StaticConstructor
- StaticDestructor
- DebugSpecification
- VersionSpecification
- ;
-
-
-
- Modules have a one-to-one correspondence with source files.
- The module name is the file name with the path and extension
- stripped off.
-
-
-
- Modules can be grouped together in heirarchies called packages.
-
-Module Declaration
-
- The ModuleDeclaration sets the name of the module and what
- package it belongs to. If absent, the module name is taken to be the
- same name (stripped of path and extension) of the source file name.
-
-
- ModuleDeclaration:
- module ModuleName ;
-
- ModuleName:
- Identifier
- ModuleName . Identifier
-
-
- The Identifier preceding the rightmost are the packages
- that the module is in. The packages correspond to directory names in
- the source file path.
-
- module c.stdio; // this is module stdio in the c package
-
-
- By convention, package and module names are all lower case. This is
- because those names have a one-to-one correspondence with the operating
- system's directory and file names, and many file systems
- are not case sensitive. All lower case package and module names will
- minimize problems moving projects between dissimilar file systems.
-
-Import Declaration
-
- Rather than text include files, D imports symbols symbolically with the
- import declaration:
-
-
- ImportDeclaration:
- import ModuleNameList ;
-
- ModuleNameList:
- ModuleName
- ModuleName , ModuleNameList
-
-
- The rightmost Identifier becomes the module name.
- The top level scope in the module is merged with the current scope.
-
- import std.c.stdio; // import module stdio from the c package
- import foo, bar; // import modules foo and bar
-
-
-Scope and Modules
-
- Each module forms its own namespace. When a module is imported
- into another module, by default all its top level declarations are
- available without qualification. Ambiguities are illegal, and
- can be resolved by explicitly qualifying the symbol with the
- module name.
-
- Module foo
- int x = 1;
- int y = 2;
-
- Module bar
- int y = 3;
- int z = 4;
-
-
- then:
-
-
- import foo;
- ...
- q = y; // sets q to foo.y
-
-
- and:
-
-
- import foo;
- int y = 5;
- q = y; // local y overrides foo.y
-
-
- and:
-
-
- import foo;
- import bar;
- q = y; // error: foo.y or bar.y?
-
-
- and:
-
-
- import foo;
- import bar;
- q = bar.y; // q set to 3
-
-
- If the import is private, such as:
-
-
- module abc;
- private import def;
-
-
- then def is not searched when another module imports abc.
-
-Module Scope Operator
-
- Sometimes, it's necessary to override the usual lexical scoping rules
- to access a name hidden by a local name. This is done with the
- global scope operator, which is a leading '.':
-
-
- int x;
-
- int foo(int x)
- {
- if (y)
- return x; // returns foo.x, not global x
- else
- return .x; // returns global x
- }
-
-
- The leading '.' means look up the name at the module scope level.
-
-Static Construction and Destruction
-
- Static constructors are code that gets executed to initialize
- a module or a class before the main() function gets called.
- Static destructors are code that gets executed after the main()
- function returns, and are normally used for releasing
- system resources.
-
-Order of Static Construction
-
- The order of static initialization is implicitly determined by
- the import declarations in each module. Each module is
- assumed to depend on any imported modules being statically
- constructed first.
- Other than following that rule, there is no imposed order
- on executing the module static constructors.
- Order of Static Construction within a Module
-
- Within a module, the static construction occurs in the lexical
- order in which they appear.
-
-Order of Static Destruction
-
- It is defined to be exactly the reverse order that static
- construction was performed in. Static destructors for individual
- modules will only be run if the corresponding static constructor
- successfully completed.
-
-Order of Unit tests
-
- Unit tests are run in the lexical order in which they appear
- within a module.
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright (c) 1999-2004 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+Modules
+
+
+
+
+ Module:
+ ModuleDeclaration DeclDefs
+ DeclDefs
+
+ DeclDefs:
+ DeclDef
+ DeclDef DeclDefs
+
+ DeclDef:
+ AttributeSpecifier
+ ImportDeclaration
+ EnumDeclaration
+ ClassDeclaration
+ InterfaceDeclaration
+ AggregateDeclaration
+ Declaration
+ Constructor
+ Destructor
+ Invariant
+ Unittest
+ StaticConstructor
+ StaticDestructor
+ DebugSpecification
+ VersionSpecification
+ ;
+
+
+
+ Modules can be grouped together in heirarchies called packages.
+
+Module Declaration
+
+ The ModuleDeclaration sets the name of the module and what
+ package it belongs to. If absent, the module name is taken to be the
+ same name (stripped of path and extension) of the source file name.
+
+
+
+
+ ModuleDeclaration:
+ module ModuleName ;
+
+ ModuleName:
+ Identifier
+ ModuleName . Identifier
+
+
+
+ module c.stdio; // this is module stdio in the c package
+
Import Declaration
+
+ Rather than text include files, D imports symbols symbolically with the
+ import declaration:
+
+
+
+
+ ImportDeclaration:
+ import ModuleNameList ;
+
+ ModuleNameList:
+ ModuleName
+ ModuleName , ModuleNameList
+
+
+
+ import std.c.stdio; // import module stdio from the c package
+ import foo, bar; // import modules foo and bar
+
Scope and Modules
+
+ Each module forms its own namespace. When a module is imported
+ into another module, by default all its top level declarations are
+ available without qualification. Ambiguities are illegal, and
+ can be resolved by explicitly qualifying the symbol with the
+ module name.
+
+
+
+ Module foo
+ int x = 1;
+ int y = 2;
+
+ Module bar
+ int y = 3;
+ int z = 4;
+
+
+
+ import foo;
+ ...
+ q = y; // sets q to foo.y
+
+
+
+ import foo;
+ int y = 5;
+ q = y; // local y overrides foo.y
+
+
+
+ import foo;
+ import bar;
+ q = y; // error: foo.y or bar.y?
+
+
+
+ import foo;
+ import bar;
+ q = bar.y; // q set to 3
+
+
+
+ module abc;
+ private import def;
+
Module Scope Operator
+
+ Sometimes, it's necessary to override the usual lexical scoping rules
+ to access a name hidden by a local name. This is done with the
+ global scope operator, which is a leading '.':
+
+
+
+
+ int x;
+
+ int foo(int x)
+ {
+ if (y)
+ return x; // returns foo.x, not global x
+ else
+ return .x; // returns global x
+ }
+
Static Construction and Destruction
+
+ Static constructors are code that gets executed to initialize
+ a module or a class before the main() function gets called.
+ Static destructors are code that gets executed after the main()
+ function returns, and are normally used for releasing
+ system resources.
+
+Order of Static Construction
+
+ The order of static initialization is implicitly determined by
+ the import declarations in each module. Each module is
+ assumed to depend on any imported modules being statically
+ constructed first.
+ Other than following that rule, there is no imposed order
+ on executing the module static constructors.
+ Order of Static Construction within a Module
+
+ Within a module, the static construction occurs in the lexical
+ order in which they appear.
+
+Order of Static Destruction
+
+ It is defined to be exactly the reverse order that static
+ construction was performed in. Static destructors for individual
+ modules will only be run if the corresponding static constructor
+ successfully completed.
+
+Order of Unit tests
+
+ Unit tests are run in the lexical order in which they appear
+ within a module.
+
+Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last modified Jul 26, 2004.
-
-
-Operator Overloading
-
- Overloading is accomplished by interpreting specially named
- struct and class member functions as being implementations of unary and
- binary operators. No additional syntax is used.
-
-Unary Operator Overloading
-
-Overloadable Unary Operators
-
- op
- opfunc
-
-
- -e
- opNeg
-
-
- +e
- opPos
-
-
- ~e
- opCom
-
-
- e++
- opPostInc
-
-
- e--
- opPostDec
-
-
- cast(type)e
- opCast
-
-
- op a
-
-
- where a is a class or struct object reference,
- is interpreted as if it was written as:
-
-
- a.opfunc()
-
-
-Overloading ++e and --e
-
- Since ++e is defined to be semantically equivalent
- to (e += 1), the expression ++e is rewritten
- as (e += 1), and then checking for operator overloading
- is done. The situation is analogous for --e.
-
-Examples
-
-
-
-
-
- class A { int opNeg(); }
- A a;
- -a; // equivalent to a.opNeg();
-
-
- class A { int opNeg(int i); }
- A a;
- -a; // equivalent to a.opNeg(), which is an error
-
- Overloading cast(type)e
-
- The member function e.opCast() is called,
- and the return value of opCast() is implicitly converted
- to type. Since functions cannot be overloaded based on
- return value, there can be only one opCast per struct or
- class.
- Overloading the cast operator does not affect implicit casts, it
- only applies to explicit casts.
-
-
- struct A
- {
- int opCast() { return 28; }
- }
-
- void test()
- {
- A a;
-
- long i = cast(long)a; // i is set to 28L
- void* p = cast(void*)a; // error, cannot implicitly
- // convert int to void*
- int j = a; // error, cannot implicitly convert
- // A to int
- }
-
-
-Binary Operator Overloading
-
-Overloadable Binary Operators
-
- op
- commutative?
- opfunc
- opfunc_r
-
-
- +
- yes
- opAdd
- opAdd_r
-
-
- -
- no
- opSub
- opSub_r
-
-
- *
- yes
- opMul
- opMul_r
-
-
- /
- no
- opDiv
- opDiv_r
-
-
- %
- no
- opMod
- opMod_r
-
-
- &
- yes
- opAnd
- opAnd_r
-
-
- |
- yes
- opOr
- opOr_r
-
-
- ^
- yes
- opXor
- opXor_r
-
-
- <<
- no
- opShl
- opShl_r
-
-
- >>
- no
- opShr
- opShr_r
-
-
- >>>
- no
- opUShr
- opUShr_r
-
-
- ~
- no
- opCat
- opCat_r
-
-
- ==
- yes
- opEquals
- -
-
-
- !=
- yes
- opEquals
- -
-
-
- <
- yes
- opCmp
- -
-
-
- <=
- yes
- opCmp
- -
-
-
- >
- yes
- opCmp
- -
-
-
- >=
- yes
- opCmp
- -
-
-
- +=
- no
- opAddAssign
- -
-
-
- -=
- no
- opSubAssign
- -
-
-
- *=
- no
- opMulAssign
- -
-
-
- /=
- no
- opDivAssign
- -
-
-
- %=
- no
- opModAssign
- -
-
-
- &=
- no
- opAndAssign
- -
-
-
- |=
- no
- opOrAssign
- -
-
-
- ^=
- no
- opXorAssign
- -
-
-
- <<=
- no
- opShlAssign
- -
-
-
- >>=
- no
- opShrAssign
- -
-
-
- >>>=
- no
- opUShrAssign
- -
-
-
- ~=
- no
- opCatAssign
- -
-
-
- a op b
-
-
- the following sequence of rules is applied, in order, to determine
- which form is used:
-
-
-
-
-
- a.opfunc(b)
- b.opfunc_r(a)
-
- If any a.opfunc or b.opfunc_r functions exist,
- then overloading is applied
- across all of them and the best match is used. If either exist,
- and there is no argument match, then it is an error.
-
- a.opfunc_r(b)
- b.opfunc(a)
-
-
- Examples
-
-
-
-
-
- class A { int opAdd(int i); }
- A a;
- a + 1; // equivalent to a.opAdd(1)
- 1 + a; // equivalent to a.opAdd(1)
-
-
- class B { int opDiv_r(int i); }
- B b;
- 1 / b; // equivalent to b.opDiv_r(1)
-
-
- class A { int opAdd(int i); }
- class B { int opAdd_r(A a); }
- A a;
- B b;
- a + 1; // equivalent to a.opAdd(1)
- a + b; // equivalent to b.opAdd_r(a)
- b + a; // equivalent to b.opAdd_r(a)
-
-
- class A { int opAdd(B b); int opAdd_r(B b); }
- class B { }
- A a;
- B b;
- a + b; // equivalent to a.opAdd(b)
- b + a; // equivalent to a.opAdd_r(b)
-
-
- class A { int opAdd(B b); int opAdd_r(B b); }
- class B { int opAdd_r(A a); }
- A a;
- B b;
- a + b; // ambiguous: a.opAdd(b) or b.opAdd_r(a)
- b + a; // equivalent to a.opAdd_r(b)
-
- Overloading == and !=
-
- Both operators use the opEquals() function. The expression
- (a == b) is rewritten as a.opEquals(b),
- and (a != b) is rewritten as !a.opEquals(b).
-
- int opEquals(Object o);
-
-
- so that every class object has an opEquals().
- Overloading <, <=, > and >=
-
- These comparison operators all use the opCmp() function.
- The expression
- (a op b) is rewritten as (a.opCmp(b) op 0).
- The commutative operation is rewritten as (0 op b.opCmp(a))
-
- int opCmp(Object o);
-
-
- so that every class object has a opCmp().
-
- if (a === null)
-
- and not as:
-
- if (a == null)
-
- The latter is converted to:
-
- if (a.opCmp(null))
-
- which will fail if opCmp() is a virtual function.
-
-Rationale
- The reason for having both opEquals() and opCmp() is that:
-
-
-
-
- class A
- {
- int opCmp(Object o)
- {
- assert(0); // comparison makes no sense
- return 0;
- }
- }
-
- Function Call Operator Overloading f()
-
- The function call operator, (), can be overloaded by
- declaring a function named opCall:
-
-
- struct F
- {
- int opCall();
- int opCall(int x, int y, int z);
- }
-
- void test()
- { F f;
- int i;
-
- i = f(); // same as i = f.opCall();
- i = f(3,4,5); // same as i = a.opCall(3,4,5);
- }
-
-
- In this way a struct or class object can behave as if it
- were a function.
-
-
-Array Operator Overloading
-
-Overloading Indexing a[i]
-
- The array index operator, [], can be overloaded by
- declaring a function named opIndex with one
- or more parameters.
- Assignment to an array can be overloaded with a function
- named opIndexAssign with two or more parameters.
- The first parameter is the rvalue of the assignment expression.
-
-
- struct A
- {
- int opIndex(int i1, int i2, int i3);
- int opIndexAssign(int value, int i1, int i2);
- }
-
- void test()
- { A a;
- int i;
-
- i = a[5,6,7]; // same as i = a.opIndex(5,6,7);
- a[i,3] = 7; // same as a.opIndexAssign(7,i,3);
- }
-
-
- In this way a struct or class object can behave as if it
- were an array.
- Overloading Slicing a[] and a[i .. j]
-
- Overloading the slicing operator means overloading expressions
- like a[] and a[i .. j].
-
-
- class A
- {
- int opSlice(); // overloads a[]
- int opSlice(int x, int y); // overloads a[i .. j]
- }
-
- void test()
- { A a = new A();
- int i;
-
- i = a[]; // same as i = a.opSlice();
- i = a[3..4]; // same as i = a.opSlice(3,4);
- }
-
-
-Future Directions
-
- The operators ., &&, ||, ?:, and a few others will likely never
- be overloadable.
- The names of the overloaded operators may change.
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright (c) 1999-2004 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+
+Operator Overloading
+
+ Overloading is accomplished by interpreting specially named
+ struct and class member functions as being implementations of unary and
+ binary operators. No additional syntax is used.
+
+Unary Operator Overloading
+
+Overloadable Unary Operators
+
+ op
+ opfunc
+
+
+ -e
+ opNeg
+
+
+ +e
+ opPos
+
+
+ ~e
+ opCom
+
+
+ e++
+ opPostInc
+
+
+ e--
+ opPostDec
+
+
+ cast(type)e
+ opCast
+
+
+ op a
+
+
+ where a is a class or struct object reference,
+ is interpreted as if it was written as:
+
+
+ a.opfunc()
+
+
+Overloading ++e and --e
+
+ Since ++e is defined to be semantically equivalent
+ to (e += 1), the expression ++e is rewritten
+ as (e += 1), and then checking for operator overloading
+ is done. The situation is analogous for --e.
+
+Examples
+
+
+
+
+
+ class A { int opNeg(); }
+ A a;
+ -a; // equivalent to a.opNeg();
+
+
+ class A { int opNeg(int i); }
+ A a;
+ -a; // equivalent to a.opNeg(), which is an error
+
+ Overloading cast(type)e
+
+ The member function e.opCast() is called,
+ and the return value of opCast() is implicitly converted
+ to type. Since functions cannot be overloaded based on
+ return value, there can be only one opCast per struct or
+ class.
+ Overloading the cast operator does not affect implicit casts, it
+ only applies to explicit casts.
+
+
+ struct A
+ {
+ int opCast() { return 28; }
+ }
+
+ void test()
+ {
+ A a;
+
+ long i = cast(long)a; // i is set to 28L
+ void* p = cast(void*)a; // error, cannot implicitly
+ // convert int to void*
+ int j = a; // error, cannot implicitly convert
+ // A to int
+ }
+
+
+Binary Operator Overloading
+
+Overloadable Binary Operators
+
+ op
+ commutative?
+ opfunc
+ opfunc_r
+
+
+ +
+ yes
+ opAdd
+ opAdd_r
+
+
+ -
+ no
+ opSub
+ opSub_r
+
+
+ *
+ yes
+ opMul
+ opMul_r
+
+
+ /
+ no
+ opDiv
+ opDiv_r
+
+
+ %
+ no
+ opMod
+ opMod_r
+
+
+ &
+ yes
+ opAnd
+ opAnd_r
+
+
+ |
+ yes
+ opOr
+ opOr_r
+
+
+ ^
+ yes
+ opXor
+ opXor_r
+
+
+ <<
+ no
+ opShl
+ opShl_r
+
+
+ >>
+ no
+ opShr
+ opShr_r
+
+
+ >>>
+ no
+ opUShr
+ opUShr_r
+
+
+ ~
+ no
+ opCat
+ opCat_r
+
+
+ ==
+ yes
+ opEquals
+ -
+
+
+ !=
+ yes
+ opEquals
+ -
+
+
+ <
+ yes
+ opCmp
+ -
+
+
+ <=
+ yes
+ opCmp
+ -
+
+
+ >
+ yes
+ opCmp
+ -
+
+
+ >=
+ yes
+ opCmp
+ -
+
+
+ +=
+ no
+ opAddAssign
+ -
+
+
+ -=
+ no
+ opSubAssign
+ -
+
+
+ *=
+ no
+ opMulAssign
+ -
+
+
+ /=
+ no
+ opDivAssign
+ -
+
+
+ %=
+ no
+ opModAssign
+ -
+
+
+ &=
+ no
+ opAndAssign
+ -
+
+
+ |=
+ no
+ opOrAssign
+ -
+
+
+ ^=
+ no
+ opXorAssign
+ -
+
+
+ <<=
+ no
+ opShlAssign
+ -
+
+
+ >>=
+ no
+ opShrAssign
+ -
+
+
+ >>>=
+ no
+ opUShrAssign
+ -
+
+
+ ~=
+ no
+ opCatAssign
+ -
+
+
+ a op b
+
+
+ the following sequence of rules is applied, in order, to determine
+ which form is used:
+
+
+
+
+
+ a.opfunc(b)
+ b.opfunc_r(a)
+
+ If any a.opfunc or b.opfunc_r functions exist,
+ then overloading is applied
+ across all of them and the best match is used. If either exist,
+ and there is no argument match, then it is an error.
+
+ a.opfunc_r(b)
+ b.opfunc(a)
+
+
+ Examples
+
+
+
+
+
+ class A { int opAdd(int i); }
+ A a;
+ a + 1; // equivalent to a.opAdd(1)
+ 1 + a; // equivalent to a.opAdd(1)
+
+
+ class B { int opDiv_r(int i); }
+ B b;
+ 1 / b; // equivalent to b.opDiv_r(1)
+
+
+ class A { int opAdd(int i); }
+ class B { int opAdd_r(A a); }
+ A a;
+ B b;
+ a + 1; // equivalent to a.opAdd(1)
+ a + b; // equivalent to b.opAdd_r(a)
+ b + a; // equivalent to b.opAdd_r(a)
+
+
+ class A { int opAdd(B b); int opAdd_r(B b); }
+ class B { }
+ A a;
+ B b;
+ a + b; // equivalent to a.opAdd(b)
+ b + a; // equivalent to a.opAdd_r(b)
+
+
+ class A { int opAdd(B b); int opAdd_r(B b); }
+ class B { int opAdd_r(A a); }
+ A a;
+ B b;
+ a + b; // ambiguous: a.opAdd(b) or b.opAdd_r(a)
+ b + a; // equivalent to a.opAdd_r(b)
+
+ Overloading == and !=
+
+ Both operators use the opEquals() function. The expression
+ (a == b) is rewritten as a.opEquals(b),
+ and (a != b) is rewritten as !a.opEquals(b).
+
+ int opEquals(Object o);
+
+
+ so that every class object has an opEquals().
+ Overloading <, <=, > and >=
+
+ These comparison operators all use the opCmp() function.
+ The expression
+ (a op b) is rewritten as (a.opCmp(b) op 0).
+ The commutative operation is rewritten as (0 op b.opCmp(a))
+
+ int opCmp(Object o);
+
+
+ so that every class object has a opCmp().
+
+ if (a === null)
+
+ and not as:
+
+ if (a == null)
+
+ The latter is converted to:
+
+ if (a.opCmp(null))
+
+ which will fail if opCmp() is a virtual function.
+
+Rationale
+ The reason for having both opEquals() and opCmp() is that:
+
+
+
+
+ class A
+ {
+ int opCmp(Object o)
+ {
+ assert(0); // comparison makes no sense
+ return 0;
+ }
+ }
+
+ Function Call Operator Overloading f()
+
+ The function call operator, (), can be overloaded by
+ declaring a function named opCall:
+
+
+ struct F
+ {
+ int opCall();
+ int opCall(int x, int y, int z);
+ }
+
+ void test()
+ { F f;
+ int i;
+
+ i = f(); // same as i = f.opCall();
+ i = f(3,4,5); // same as i = a.opCall(3,4,5);
+ }
+
+
+ In this way a struct or class object can behave as if it
+ were a function.
+
+
+Array Operator Overloading
+
+Overloading Indexing a[i]
+
+ The array index operator, [], can be overloaded by
+ declaring a function named opIndex with one
+ or more parameters.
+ Assignment to an array can be overloaded with a function
+ named opIndexAssign with two or more parameters.
+ The first parameter is the rvalue of the assignment expression.
+
+
+ struct A
+ {
+ int opIndex(int i1, int i2, int i3);
+ int opIndexAssign(int value, int i1, int i2);
+ }
+
+ void test()
+ { A a;
+ int i;
+
+ i = a[5,6,7]; // same as i = a.opIndex(5,6,7);
+ a[i,3] = 7; // same as a.opIndexAssign(7,i,3);
+ }
+
+
+ In this way a struct or class object can behave as if it
+ were an array.
+ Overloading Slicing a[] and a[i .. j]
+
+ Overloading the slicing operator means overloading expressions
+ like a[] and a[i .. j].
+
+
+ class A
+ {
+ int opSlice(); // overloads a[]
+ int opSlice(int x, int y); // overloads a[i .. j]
+ }
+
+ void test()
+ { A a = new A();
+ int i;
+
+ i = a[]; // same as i = a.opSlice();
+ i = a[3..4]; // same as i = a.opSlice(3,4);
+ }
+
+
+Future Directions
+
+ The operators ., &&, ||, ?:, and a few others will likely never
+ be overloadable.
+ The names of the overloaded operators may change.
+
+Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last update Mar 4, 2005
-
-
-Overview
-
-What is D?
-
- D is a general purpose systems and applications programming language.
- It is a higher level language than C++, but retains the ability
- to write high performance code and interface directly with the
- operating system
- API's
- and with hardware.
- D is well suited to writing medium to large scale
- million line programs with teams of developers. D is easy
- to learn, provides many capabilities to aid the programmer,
- and is well suited to aggressive compiler optimization technology.
- Why D?
-
- Why, indeed. Who needs another programming language?
- Major Goals of D
-
-
-
-
-
-Features To Keep From C/C++
-
- The general look of D is like C and C++. This makes it easier to learn
- and port code to D. Transitioning from C/C++ to D should feel natural.
- The
- programmer will not have to learn an entirely new way of doing things.
-
-
-
-Features To Drop
-
-
-
-
-Who D is For
-
-
-
-
-Who D is Not For
-
-
-
-
-
-Major Features of D
-
- This section lists some of the more interesting features of D
- in various categories.
-
-Object Oriented Programming
-
- Classes
-
- D's object oriented nature comes from classes.
- The inheritance model is single inheritance enhanced
- with interfaces. The class Object sits at the root
- of the inheritance hierarchy, so all classes implement
- a common set of functionality.
- Classes are instantiated
- by reference, and so complex code to clean up after exceptions
- is not required.
-
- Operator Overloading
-
- Classes can be crafted that work with existing operators to extend
- the type system to support new types. An example would be creating
- a bignumber class and then overloading the +, -, * and / operators
- to enable using ordinary algebraic syntax with them.
-
-Productivity
-
- Modules
-
- Source files have a one-to-one correspondence with modules.
- Instead of #include'ing the text of a file of declarations,
- just import the module. There is no need to worry about
- multiple imports of the same module, no need to wrapper header
- files with #ifndef/#endif or #pragma once kludges,
- etc.
-
- Declaration vs Definition
-
- C++ usually requires that functions and classes be declared twice - the declaration
- that goes in the .h header file, and the definition that goes in the .c source
- file. This is an error prone and tedious process. Obviously, the programmer
- should only need to write it once, and the compiler should then extract the
- declaration information and make it available for symbolic importing. This is
- exactly how D works.
-
- class ABC
- {
- int func() { return 7; }
- static int z = 7;
- }
- int q;
-
-
- There is no longer a need for a separate definition of member functions, static
- members, externs, nor for clumsy syntaxes like:
-
-
- int ABC::func() { return 7; }
- int ABC::z = 7;
- extern int q;
-
-
- Note: Of course, in C++, trivial functions like { return 7; }
- are written inline too, but complex ones are not. In addition, if
- there are any forward references, the functions need to be prototyped.
- The following will not work in C++:
-
-
- class Foo
- {
- int foo(Bar *c) { return c->bar; }
- };
-
- class Bar
- {
- public:
- int bar() { return 3; }
- };
-
-
- But the equivalent D code will work:
-
-
- class Foo
- {
- int foo(Bar c) { return c.bar; }
- }
-
- class Bar
- {
- int bar() { return 3; }
- }
-
-
- Whether a D function is inlined or not is determined by the
- optimizer settings.
-
- Templates
-
- D templates offer a clean way to support generic programming while
- offering the power of partial specialization.
-
- Associative Arrays
-
- Associative arrays are arrays with an arbitrary data type as
- the index rather than being limited to an integer index.
- In essence, associated arrays are hash tables. Associative
- arrays make it easy to build fast, efficient, bug-free symbol
- tables.
-
- Real Typedefs
-
- C and C++ typedefs are really type aliases, as no new
- type is really introduced. D implements real typedefs, where:
-
-
- typedef int handle;
-
-
- really does create a new type handle. Type checking is
- enforced, and typedefs participate in function overloading.
- For example:
-
-
- int foo(int i);
- int foo(handle h);
-
-
- Bit type
-
- The fundamental data type is the bit, and D has a bit data
- type. This is most useful in creating arrays of bits:
-
-
- bit[] foo;
-
-
-Functions
-
- D has the expected support for ordinary functions including
- global functions, overloaded functions, inlining of functions,
- member functions, virtual functions, function pointers, etc.
- In addition:
-
- Nested Functions
-
- Functions can be nested within other functions.
- This is highly useful for code factoring, locality, and
- function closure techniques.
-
- Function Literals
-
- Anonymous functions can be embedded directly into an expression.
-
- Dynamic Closures
-
- Nested functions and class member functions can be referenced
- with closures (also called delegates), making generic programming
- much easier and type safe.
-
- In, Out, and Inout Parameters
-
- Not only does specifying this help make functions more
- self-documenting, it eliminates much of the necessity for pointers
- without sacrificing anything, and it opens up possibilities
- for more compiler help in finding coding problems.
- Arrays
-
- C arrays have several faults that can be corrected:
-
-
-
-
- D arrays come in 4 varieties: pointers, static arrays, dynamic
- arrays, and associative arrays.
-
- See Arrays.
-
-
- int (*array)[3];
-
-
- In D, the [] for the array go on the left:
-
-
- int[3]* array; declares a pointer to an array of 3 ints
- long[] func(int x); declares a function returning an array of longs
-
-
- which is much simpler to understand.
- Strings
-
- String manipulation is so common, and so clumsy in C and C++, that
- it needs direct support in the language. Modern languages handle
- string concatenation, copying, etc., and so does D. Strings are
- a direct consequence of improved array handling.
-
-Resource Management
-
- Garbage Collection
-
- D memory allocation is fully garbage collected. Empirical experience
- suggests that a lot of the complicated features of C++ are necessary
- in order to manage memory deallocation. With garbage collection, the
- language gets much simpler.
- Explicit Memory Management
-
- Despite D being a garbage collected language, the new and delete
- operations can be overridden for particular classes so that
- a custom allocator can be used.
-
- RAII
-
- RAII is a modern software development technique to manage resource
- allocation and deallocation. D supports RAII in a controlled,
- predictable manner that is independent of the garbage collection
- cycle.
-
-
-Performance
-
- Lightweight Aggregates
-
- D supports simple C style struct's, both for compatibility with
- C data structures and because they're useful when the full power
- of classes is overkill.
-
- Inline Assembler
-
- Device drivers, high performance system applications, embedded systems,
- and specialized code sometimes need to dip into assembly language
- to get the job done. While D implementations are not required
- to implement the inline assembler, it is defined and part of the
- language. Most assembly code needs can be handled with it,
- obviating the need for separate assemblers or DLL's.
- Reliability
-
- A modern language should do all it can to help the programmer flush
- out bugs in the code. Help can come in many forms;
- from making it easy to use more robust techniques,
- to compiler flagging of obviously incorrect code, to runtime checking.
-
- Contracts
-
- Contract Programming (invented by B. Meyer) is a revolutionary technique
- to aid in ensuring the correctness of programs. D's version of
- DBC includes function preconditions, function postconditions, class
- invariants, and assert contracts.
- See Contracts for D's implementation.
-
- Unit Tests
-
- Unit tests can be added to a class, such that they are automatically
- run upon program startup. This aids in verifying, in every build,
- that class implementations weren't inadvertantly broken. The unit
- tests form part of the source code for a class. Creating them
- becomes a natural part of the class development process, as opposed
- to throwing the finished code over the wall to the testing group.
- Debug Attributes and Statements
-
- Now debug is part of the syntax of the language.
- The code can be enabled or disabled at compile time, without the
- use of macros or preprocessing commands. The debug syntax enables
- a consistent, portable, and understandable recognition that real
- source code needs to be able to generate both debug compilations and
- release compilations.
-
- Exception Handling
-
- The superior try-catch-finally model is used rather than just
- try-catch. There's no need to create dummy objects just to have
- the destructor implement the finally semantics.
-
- Synchronization
-
- Multithreaded programming is becoming more and more mainstream,
- and D provides primitives to build multithreaded programs with.
- Synchronization can be done at either the method or the object level.
-
-
- synchronized int func() { . }
-
-
- Synchronized functions allow only one thread at a time to be executing that
- function.
- Support for Robust Techniques
-
-
-
-
- Compile Time Checks
-
-
-
-
- Runtime Checking
-
-
-
-
-
-Compatibility
-
- Operator precedence and evaluation rules
-
- D retains C operators and their precedence rules, order of
- evaluation rules, and promotion rules. This avoids subtle
- bugs that might arise from being so used to the way C
- does things that one has a great deal of trouble finding
- bugs due to different semantics.
-
- Direct Access to C API's
-
- Not only does D have data types that correspond to C types,
- it provides direct access to C functions. There is no need
- to write wrapper functions, parameter swizzlers, nor code to copy
- aggregate members one by one.
-
- Support for all C data types
-
- Making it possible to interface to any C API or existing C
- library code. This support includes structs, unions, enums,
- pointers, and all C99 types.
- D includes the capability to
- set the alignment of struct members to ensure compatibility with
- externally imposed data formats.
-
- OS Exception Handling
-
- D's exception handling mechanism will connect to the way
- the underlying operating system handles exceptions in
- an application.
-
- Uses Existing Tools
-
- D produces code in standard object file format, enabling the use
- of standard assemblers, linkers, debuggers, profilers, exe compressors,
- and other analyzers, as well as linking to code written in other
- languages.
-
-Project Management
-
- Versioning
-
- D provides built-in support for generation of multiple versions
- of a program from the same text. It replaces the C preprocessor
- #if/#endif technique.
- Deprecation
-
- As code evolves over time, some old library code gets replaced
- with newer, better versions. The old versions must be available
- to support legacy code, but they can be marked as deprecated.
- Code that uses deprecated versions will be normally flagged
- as illegal, but would be allowed by a compiler switch.
- This will making it easy for maintenance
- programmers to identify any dependence on deprecated features.
-
- No Warnings
-
- D compilers will not generate warnings for questionable code.
- Code will either be acceptable to the compiler or it will not be.
- This will eliminate any debate about which warnings are valid
- errors and which are not, and any debate about what to do with them.
- The need for compiler warnings is symptomatic of poor language design.
-
-
-Sample D Program (sieve.d)
-
-
-
-/* Sieve of Eratosthenes prime numbers */
-
-bit[8191] flags;
-
-int main()
-{ int i, count, prime, k, iter;
-
- printf("10 iterations\n");
- for (iter = 1; iter <= 10; iter++)
- { count = 0;
- flags[] = 1;
- for (i = 0; i < flags.length; i++)
- { if (flags[i])
- { prime = i + i + 3;
- k = i + prime;
- while (k < flags.length)
- {
- flags[k] = 0;
- k += prime;
- }
- count += 1;
- }
- }
- }
- printf ("\n%d primes", count);
- return 0;
-}
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Last update Thu May 19 2005
+
+
+Overview
+
+What is D?
+
+ D is a general purpose systems and applications programming language.
+ It is a higher level language than C++, but retains the ability
+ to write high performance code and interface directly with the
+ operating system
+ API's
+ and with hardware.
+ D is well suited to writing medium to large scale
+ million line programs with teams of developers. D is easy
+ to learn, provides many capabilities to aid the programmer,
+ and is well suited to aggressive compiler optimization technology.
+ Why D?
+
+ Why, indeed. Who needs another programming language?
+ Major Goals of D
+
+
+
+
+
+Features To Keep From C/C++
+
+ The general look of D is like C and C++. This makes it easier to learn
+ and port code to D. Transitioning from C/C++ to D should feel natural.
+ The
+ programmer will not have to learn an entirely new way of doing things.
+
+
+
+Features To Drop
+
+
+
+
+Who D is For
+
+
+
+
+Who D is Not For
+
+
+
+
+
+Major Features of D
+
+ This section lists some of the more interesting features of D
+ in various categories.
+
+Object Oriented Programming
+
+ Classes
+
+ D's object oriented nature comes from classes.
+ The inheritance model is single inheritance enhanced
+ with interfaces. The class Object sits at the root
+ of the inheritance hierarchy, so all classes implement
+ a common set of functionality.
+ Classes are instantiated
+ by reference, and so complex code to clean up after exceptions
+ is not required.
+
+ Operator Overloading
+
+ Classes can be crafted that work with existing operators to extend
+ the type system to support new types. An example would be creating
+ a bignumber class and then overloading the +, -, * and / operators
+ to enable using ordinary algebraic syntax with them.
+
+Productivity
+
+ Modules
+
+ Source files have a one-to-one correspondence with modules.
+ Instead of #include'ing the text of a file of declarations,
+ just import the module. There is no need to worry about
+ multiple imports of the same module, no need to wrapper header
+ files with #ifndef/#endif or #pragma once kludges,
+ etc.
+
+ Declaration vs Definition
+
+ C++ usually requires that functions and classes be declared twice - the declaration
+ that goes in the .h header file, and the definition that goes in the .c source
+ file. This is an error prone and tedious process. Obviously, the programmer
+ should only need to write it once, and the compiler should then extract the
+ declaration information and make it available for symbolic importing. This is
+ exactly how D works.
+
+ class ABC
+ {
+ int func() { return 7; }
+ static int z = 7;
+ }
+ int q;
+
+
+ There is no longer a need for a separate definition of member functions, static
+ members, externs, nor for clumsy syntaxes like:
+
+
+ int ABC::func() { return 7; }
+ int ABC::z = 7;
+ extern int q;
+
+
+ Note: Of course, in C++, trivial functions like { return 7; }
+ are written inline too, but complex ones are not. In addition, if
+ there are any forward references, the functions need to be prototyped.
+ The following will not work in C++:
+
+
+ class Foo
+ {
+ int foo(Bar *c) { return c->bar; }
+ };
+
+ class Bar
+ {
+ public:
+ int bar() { return 3; }
+ };
+
+
+ But the equivalent D code will work:
+
+
+ class Foo
+ {
+ int foo(Bar c) { return c.bar; }
+ }
+
+ class Bar
+ {
+ int bar() { return 3; }
+ }
+
+
+ Whether a D function is inlined or not is determined by the
+ optimizer settings.
+
+ Templates
+
+ D templates offer a clean way to support generic programming while
+ offering the power of partial specialization.
+
+ Associative Arrays
+
+ Associative arrays are arrays with an arbitrary data type as
+ the index rather than being limited to an integer index.
+ In essence, associated arrays are hash tables. Associative
+ arrays make it easy to build fast, efficient, bug-free symbol
+ tables.
+
+ Real Typedefs
+
+ C and C++ typedefs are really type aliases, as no new
+ type is really introduced. D implements real typedefs, where:
+
+
+ typedef int handle;
+
+
+ really does create a new type handle. Type checking is
+ enforced, and typedefs participate in function overloading.
+ For example:
+
+
+ int foo(int i);
+ int foo(handle h);
+
+
+ Bit type
+
+ The fundamental data type is the bit, and D has a bit data
+ type. This is most useful in creating arrays of bits:
+
+
+ bit[] foo;
+
+
+Functions
+
+ D has the expected support for ordinary functions including
+ global functions, overloaded functions, inlining of functions,
+ member functions, virtual functions, function pointers, etc.
+ In addition:
+
+ Nested Functions
+
+ Functions can be nested within other functions.
+ This is highly useful for code factoring, locality, and
+ function closure techniques.
+
+ Function Literals
+
+ Anonymous functions can be embedded directly into an expression.
+
+ Dynamic Closures
+
+ Nested functions and class member functions can be referenced
+ with closures (also called delegates), making generic programming
+ much easier and type safe.
+
+ In, Out, and Inout Parameters
+
+ Not only does specifying this help make functions more
+ self-documenting, it eliminates much of the necessity for pointers
+ without sacrificing anything, and it opens up possibilities
+ for more compiler help in finding coding problems.
+ Arrays
+
+ C arrays have several faults that can be corrected:
+
+
+
+
+ D arrays come in 4 varieties: pointers, static arrays, dynamic
+ arrays, and associative arrays.
+
+ See Arrays.
+
+
+ int (*array)[3];
+
+
+ In D, the [] for the array go on the left:
+
+
+ int[3]* array; declares a pointer to an array of 3 ints
+ long[] func(int x); declares a function returning an array of longs
+
+
+ which is much simpler to understand.
+ Strings
+
+ String manipulation is so common, and so clumsy in C and C++, that
+ it needs direct support in the language. Modern languages handle
+ string concatenation, copying, etc., and so does D. Strings are
+ a direct consequence of improved array handling.
+
+Resource Management
+
+ Garbage Collection
+
+ D memory allocation is fully garbage collected. Empirical experience
+ suggests that a lot of the complicated features of C++ are necessary
+ in order to manage memory deallocation. With garbage collection, the
+ language gets much simpler.
+ Explicit Memory Management
+
+ Despite D being a garbage collected language, the new and delete
+ operations can be overridden for particular classes so that
+ a custom allocator can be used.
+
+ RAII
+
+ RAII is a modern software development technique to manage resource
+ allocation and deallocation. D supports RAII in a controlled,
+ predictable manner that is independent of the garbage collection
+ cycle.
+
+
+Performance
+
+ Lightweight Aggregates
+
+ D supports simple C style struct's, both for compatibility with
+ C data structures and because they're useful when the full power
+ of classes is overkill.
+
+ Inline Assembler
+
+ Device drivers, high performance system applications, embedded systems,
+ and specialized code sometimes need to dip into assembly language
+ to get the job done. While D implementations are not required
+ to implement the inline assembler, it is defined and part of the
+ language. Most assembly code needs can be handled with it,
+ obviating the need for separate assemblers or DLL's.
+ Reliability
+
+ A modern language should do all it can to help the programmer flush
+ out bugs in the code. Help can come in many forms;
+ from making it easy to use more robust techniques,
+ to compiler flagging of obviously incorrect code, to runtime checking.
+
+ Contracts
+
+ Contract Programming (invented by B. Meyer) is a revolutionary technique
+ to aid in ensuring the correctness of programs. D's version of
+ DBC includes function preconditions, function postconditions, class
+ invariants, and assert contracts.
+ See Contracts for D's implementation.
+
+ Unit Tests
+
+ Unit tests can be added to a class, such that they are automatically
+ run upon program startup. This aids in verifying, in every build,
+ that class implementations weren't inadvertantly broken. The unit
+ tests form part of the source code for a class. Creating them
+ becomes a natural part of the class development process, as opposed
+ to throwing the finished code over the wall to the testing group.
+ Debug Attributes and Statements
+
+ Now debug is part of the syntax of the language.
+ The code can be enabled or disabled at compile time, without the
+ use of macros or preprocessing commands. The debug syntax enables
+ a consistent, portable, and understandable recognition that real
+ source code needs to be able to generate both debug compilations and
+ release compilations.
+
+ Exception Handling
+
+ The superior try-catch-finally model is used rather than just
+ try-catch. There's no need to create dummy objects just to have
+ the destructor implement the finally semantics.
+
+ Synchronization
+
+ Multithreaded programming is becoming more and more mainstream,
+ and D provides primitives to build multithreaded programs with.
+ Synchronization can be done at either the method or the object level.
+
+
+ synchronized int func() { . }
+
+
+ Synchronized functions allow only one thread at a time to be executing that
+ function.
+ Support for Robust Techniques
+
+
+
+
+ Compile Time Checks
+
+
+
+
+ Runtime Checking
+
+
+
+
+
+Compatibility
+
+ Operator precedence and evaluation rules
+
+ D retains C operators and their precedence rules, order of
+ evaluation rules, and promotion rules. This avoids subtle
+ bugs that might arise from being so used to the way C
+ does things that one has a great deal of trouble finding
+ bugs due to different semantics.
+
+ Direct Access to C API's
+
+ Not only does D have data types that correspond to C types,
+ it provides direct access to C functions. There is no need
+ to write wrapper functions, parameter swizzlers, nor code to copy
+ aggregate members one by one.
+
+ Support for all C data types
+
+ Making it possible to interface to any C API or existing C
+ library code. This support includes structs, unions, enums,
+ pointers, and all C99 types.
+ D includes the capability to
+ set the alignment of struct members to ensure compatibility with
+ externally imposed data formats.
+
+ OS Exception Handling
+
+ D's exception handling mechanism will connect to the way
+ the underlying operating system handles exceptions in
+ an application.
+
+ Uses Existing Tools
+
+ D produces code in standard object file format, enabling the use
+ of standard assemblers, linkers, debuggers, profilers, exe compressors,
+ and other analyzers, as well as linking to code written in other
+ languages.
+
+Project Management
+
+ Versioning
+
+ D provides built-in support for generation of multiple versions
+ of a program from the same text. It replaces the C preprocessor
+ #if/#endif technique.
+ Deprecation
+
+ As code evolves over time, some old library code gets replaced
+ with newer, better versions. The old versions must be available
+ to support legacy code, but they can be marked as deprecated.
+ Code that uses deprecated versions will be normally flagged
+ as illegal, but would be allowed by a compiler switch.
+ This will making it easy for maintenance
+ programmers to identify any dependence on deprecated features.
+
+ No Warnings
+
+ D compilers will not generate warnings for questionable code.
+ Code will either be acceptable to the compiler or it will not be.
+ This will eliminate any debate about which warnings are valid
+ errors and which are not, and any debate about what to do with them.
+ The need for compiler warnings is symptomatic of poor language design.
+
+
+Sample D Program (sieve.d)
+
+
+
+
+/* Sieve of Eratosthenes prime numbers */
+
+bit[8191] flags;
+
+int main()
+{ int i, count, prime, k, iter;
+
+ printf("10 iterations\n");
+ for (iter = 1; iter <= 10; iter++)
+ { count = 0;
+ flags[] = 1;
+ for (i = 0; i < flags.length; i++)
+ { if (flags[i])
+ { prime = i + i + 3;
+ k = i + prime;
+ while (k < flags.length)
+ {
+ flags[k] = 0;
+ k += prime;
+ }
+ count += 1;
+ }
+ }
+ }
+ printf ("\n%d primes", count);
+ return 0;
+}
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last update Feb 20, 2005
-
-
-Phobos
D Runtime Library
Philosophy
-
- Each module in Phobos conforms as much as possible to the
- following design goals. These are goals
- rather than requirements because D is not a religion,
- it's a programming language, and it recognizes that
- sometimes the goals are contradictory and counterproductive
- in certain situations, and programmers have
- jobs that need to get done.
-
-
-
-
-
-
-
-Imports
-
- Runtime library modules can be imported with the
- import statement. Each module falls into one of several
- packages:
-
-
-
-
-
-
-
-
-
-
-
-
-
-std: Core library modules
-
-
-
-
-
-
-std.windows: Modules specific to the Windows operating system
-
-
-
-
-
-
-std.linux: Modules specific to the Linux operating system
-
-
-std.c: Interface to C functions
-
-
-
-
-
-
-std.c.windows: Interface to C Windows functions
-
-
-
-
-
-
-std.c.linux: Interface to C Linux functions
-
-
-
-
-
-
-
-
-std.base64
-
-Encodes/decodes base64 data.
-
-
-std.compiler
-
-
-
-
-
-
-
-
-std.conv
-
- std.conv provides basic building blocks for conversions from
- strings to integral types. They differ from the C functions atoi()
- and atol() by not allowing whitespace or overflows.
-
- Integer:
- Sign UnsignedInteger
- UnsignedInteger
-
- Sign:
- +
- -
-
-
- For conversion to unsigned types, the grammar recognized is:
-
-
- UnsignedInteger:
- DecimalDigit
- DecimalDigit UnsignedInteger
-
-
- Any deviation from that grammar causes a ConvError exception
- to be thrown. Any overflows cause a ConvOverflowError to
- be thrown.
-
-
-
-
-
-
-std.ctype
-
-
-
-
-
-
-std.date
-
- Dates are represented in several formats. The date implementation
- revolves around a central type, d_time, from which other
- formats are converted to and from.
-
-
-
-
-std.file
-
-
-
-
-
-
-std.gc
-
- The garbage collector normally works behind the scenes without
- needing any specific interaction. These functions are for
- advanced applications that benefit from tuning the operation of the
- collector.
-
-
-
-
-
-std.intrinsic
-
- Intrinsic functions are functions built in to the compiler,
- usually to take advantage of specific CPU features that
- are inefficient to handle via external functions.
- The compiler's optimizer and code generator are fully
- integrated in with intrinsic functions, bringing to bear
- their full power on them.
- This can result in some surprising speedups.
-
-
-
-
-
-
-
-
- Output
- import std.intrinsic;
-
- int main()
- {
- uint v;
- int x;
-
- v = 0x21;
- x = bsf(v);
- printf("bsf(x%x) = %d\n", v, x);
- x = bsr(v);
- printf("bsr(x%x) = %d\n", v, x);
- return 0;
- }
-
-
-
- bsf(x21) = 0
- bsr(x21) = 5
-
-
-
- p[index / (uint.size*8)] & (1 << (index & ((uint.size*8) - 1)))
-
-
-
- Output
-
- import std.intrinsic;
-
- int main()
- {
- uint array[2];
-
- array[0] = 2;
- array[1] = 0x100;
-
- printf("btc(array, 35) = %d\n", btc(array, 35));
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
-
- printf("btc(array, 35) = %d\n", btc(array, 35));
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
-
- printf("bts(array, 35) = %d\n", bts(array, 35));
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
-
- printf("btr(array, 35) = %d\n", btr(array, 35));
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
-
- printf("bt(array, 1) = %d\n", bt(array, 1));
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
-
- return 0;
- }
-
-
- btc(array, 35) = 0
- array = [0]:x2, [1]:x108
- btc(array, 35) = -1
- array = [0]:x2, [1]:x100
- bts(array, 35) = 0
- array = [0]:x2, [1]:x108
- btr(array, 35) = -1
- array = [0]:x2, [1]:x100
- bt(array, 1) = -1
- array = [0]:x2, [1]:x100
-
-
-std.math
-
-
-
-
-
-
- Special values:
-
-
-
- x
- return value
- invalid?
-
- ±INFINITY
- NAN
- yes
-
- Special values:
-
-
-
- x
- return value
- invalid?
-
- ±0.0
- ±0.0
- no
-
- ±INFINITY
- NAN
- yes
-
- Special values:
-
-
-
- x
- return value
- invalid?
-
- ±0.0
- ±0.0
- no
-
- ±INFINITY
- NAN
- yes
-
- value=x*2exp
- .5 <= |x| < 1.0
- x has same sign as value.
-
- Special values:
-
-
-
- value x exp
-
- +-0.0 +-0.0 0
-
- +INFINITY +INFINITY int.max
-
- -INFINITY -INFINITY int.min
-
- +-NAN +-NAN int.min
-
- Special values:
-
-
-
- x return value divide by 0? invalid?
-
- ±0.0 -INFINITY yes no
-
- < 0.0 NAN no yes
-
- +INFINITY +INFINITY no no
-
- Special values:
-
-
-
- x return value divide by 0? invalid?
-
- ±0.0 -INFINITY yes no
-
- < 0.0 NAN no yes
-
- +INFINITY +INFINITY no no
-
- Special values:
-
-
-
- x
- return value
- invalid?
-
- -0.0
- -0.0
- no
-
- <0.0
- NAN
- yes
-
- +INFINITY
- +INFINITY
- no
-
- Special values:
-
-
-
- x
- log1p(x)
- divide by 0?
- invalid?
-
- ±0.0
- ±0.0
- no
- no
-
- -1.0
- -INFINITY
- yes
- no
-
- <-1.0
- NAN
- no
- yes
-
- +INFINITY
- -INFINITY
- no
- no
-
- Special values:
-
-
-
- x
- ex-1
-
- ±0.0
- ±0.0
-
- +INFINITY
- +INFINITY
-
- -INFINITY
- -1.0
-
- sqrt(x2 + y2)
- Note that hypot(x,y), hypot(y,x) and
- hypot(x,-y) are equivalent.
- Special values:
-
-
-
- x
- y
- return value
- invalid?
-
- x
- +-0.0
- fabs(x)
- no
-
- +-INFINITY
- y
- +INFINITY
- no
-
- +-INFINITY
- NAN
- +INFINITY
- no
-
-std.md5
-
-Computes MD5 digests of arbitrary data. MD5 digests are 16 byte quantities
-that are like a checksum or crc, but are more robust.
-
-
-
-
-
-
-
-
-Example
-
-
-// This code is derived from the
-// RSA Data Security, Inc. MD5 Message-Digest Algorithm.
-
-import std.md5;
-import std.string;
-import std.c.stdio;
-
-int main(char[][] args)
-{
- for (int i = 1; i < args.length; i++)
- MDFile(args[i]);
- return 0;
-}
-
-/* Digests a file and prints the result. */
-void MDFile(char[] filename)
-{
- FILE* file;
- MD5_CTX context;
- int len;
- ubyte [4 * 1024] buffer;
- ubyte digest[16];
-
- if ((file = fopen(std.string.toStringz(filename), "rb")) == null)
- printf("%.*s can't be opened\n", filename);
- else
- {
- context.start();
- while ((len = fread(buffer, 1, buffer.size, file)) != 0)
- context.update(buffer[0 .. len]);
- context.finish(digest);
- fclose(file);
-
- printf("MD5 (%.*s) = ", filename);
- printDigest(digest);
- printf("\n");
- }
-}
-
-
-
-
-object
-
-This module is implicitly imported.
-
-
-
-
-
-
-
-
-
-
-
-std.outbuffer
-
-
-
-
-
-
-
-
-
-std.path
-
-
-
-
-
-
-
- Matching is case sensitive on a file system that is case sensitive.
- Returns:
-
-
-
-std.process
-
-
-
-
-
-
-std.random
-
-
-
-
-
-
-std.socketstream
-
-
-
-
-
-
-
-
-
-
wchar[] readLineW()
- Notes
-
- For Win32 systems, link with ws2_32.lib.
-
-Example
-
- See /dmd/samples/d/htmlget.d.
-
-
-std.stdint
-
- D constrains integral types to specific sizes. But efficiency
- of different sizes varies from machine to machine,
- pointer sizes vary, and the maximum integer size varies.
- stdint offers a portable way of trading off size
- vs efficiency, in a manner compatible with the stdint.h
- definitions in C.
-
-
- Exact Alias
- Description
- At Least Alias
- Description
- Fast Alias
- Description
-
- int8_t
- exactly 8 bits signed
- int_least8_t
- at least 8 bits signed
- int_fast8_t
- fast 8 bits signed
-
- uint8_t
- exactly 8 bits unsigned
- uint_least8_t
- at least 8 bits unsigned
- uint_fast8_t
- fast 8 bits unsigned
-
-
- int16_t
- exactly 16 bits signed
- int_least16_t
- at least 16 bits signed
- int_fast16_t
- fast 16 bits signed
-
- uint16_t
- exactly 16 bits unsigned
- uint_least16_t
- at least 16 bits unsigned
- uint_fast16_t
- fast 16 bits unsigned
-
-
- int32_t
- exactly 32 bits signed
- int_least32_t
- at least 32 bits signed
- int_fast32_t
- fast 32 bits signed
-
- uint32_t
- exactly 32 bits unsigned
- uint_least32_t
- at least 32 bits unsigned
- uint_fast32_t
- fast 32 bits unsigned
-
-
- int64_t
- exactly 64 bits signed
- int_least64_t
- at least 64 bits signed
- int_fast64_t
- fast 64 bits signed
-
- uint64_t
- exactly 64 bits unsigned
- uint_least64_t
- at least 64 bits unsigned
- uint_fast64_t
- fast 64 bits unsigned
-
-
- Alias
- Description
-
- intptr_t
- signed integral type large enough to hold a pointer
-
- uintptr_t
- unsigned integral type large enough to hold a pointer
-
-
-
-Alias
- Description
-
- intmax_t
- the largest signed integral type
-
- uintmax_t
- the largest unsigned integral type
-
-std.stdio
-
- Standard I/O functions that extend std.c.stdio.
- std.c.stdio is automatically imported when importing
- std.stdio.
-
-
-
-
-
-std.stream
-
-
-
-
-
-
-
-
-
-
-
void read(out ubyte x)
-
void read(out short x)
-
void read(out ushort x)
-
void read(out int x)
-
void read(out uint x)
-
void read(out long x)
-
void read(out ulong x)
-
void read(out float x)
-
void read(out double x)
-
void read(out real x)
-
void read(out ifloat x)
-
void read(out idouble x)
-
void read(out ireal x)
-
void read(out cfloat x)
-
void read(out cdouble x)
-
void read(out creal x)
-
void read(out char x)
-
void read(out wchar x)
-
void read(out dchar x)
-
void read(out char[] s)
-
void read(out wchar[] s)
-
wchar[] readLineW()
-
wchar[] readLineW(wchar[] buffer)
-
wchar getcw()
-
wchar ungetcw(wchar c)
-
int vscanf(char[] fmt, va_list args)
-
-
-
-
-
-
void write(ubyte x)
-
void write(short x)
-
void write(ushort x)
-
void write(int x)
-
void write(uint x)
-
void write(long x)
-
void write(ulong x)
-
void write(float x)
-
void write(double x)
-
void write(real x)
-
void write(ifloat x)
-
void write(idouble x)
-
void write(ireal x)
-
void write(cfloat x)
-
void write(cdouble x)
-
void write(creal x)
-
void write(char x)
-
void write(wchar x)
-
void write(dchar x)
-
void write(char[] s)
-
void write(wchar[] s)
-
-
-
-
- Reading
- Writing
- Seeking
- seek(0, SeekPos.Current)
or
- seek(pos, SeekPos.Set)
respectively.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-std.system
-
-
-
-
-
-
-
-
-std.thread
-
- The thread module defines the class Thread.
- Thread is the basis
- for writing multithreaded applications. Each thread
- has a unique instance of class Thread associated with it.
- It is important to use the Thread class to create and manage
- threads as the garbage collector needs to know about all the threads.
-
-
-
- The members of Thread are:
-
-
-
-
-
-
-
- TS
- Description
-
- INITIAL
- The thread hasn't been started yet.
-
- RUNNING
- The thread is running or paused.
-
- TERMINATED
- The thread has ended.
-
-
-
- PRIORITY
- Description
-
- INCREASE
- Increase thread priority
-
- DECREASE
- Decrease thread priority
-
- IDLE
- Assign thread low priority
-
- CRITICAL
- Assign thread high priority
-
-std.uri
-
- Encode and decode Uniform Resource Identifiers (URIs).
- URIs are used in internet transfer protocols.
- Valid URI characters consist of letters, digits, and
- the characters ;/?:@&=+$,-_.!~*'(). Escape sequences
- consist of '%' followed by two hex digits.
-
-
-
-
-
-std.utf
-
- Encode and decode UTF-8, UTF-16 and UTF-32 strings.
- For more information on UTF-8, see
- http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8.
-
-
-
-
-
-
-std.zip
-
- Read/write data in the zip archive format.
- Makes use of the zlib compression library.
-
-
-
- Bugs:
-
-
-
-
- ZipArchive archive = new ZipArchive(data);
-foreach (ArchiveMember am; archive)
-{
- printf("member name is '%.*s'\n", am.name);
-}
-
-
-
-
-
-
-
-std.zlib
-
- Compress / decompress data using the
- zlib library.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-std.c.stdio
-
-
-
-
-
Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Last update Thu May 19 2005
+
+
+
+Phobos
D Runtime Library
Philosophy
+
+ Each module in Phobos conforms as much as possible to the
+ following design goals. These are goals
+ rather than requirements because D is not a religion,
+ it's a programming language, and it recognizes that
+ sometimes the goals are contradictory and counterproductive
+ in certain situations, and programmers have
+ jobs that need to get done.
+
+
+
+
+
+
+
+Imports
+
+ Runtime library modules can be imported with the
+ import statement. Each module falls into one of several
+ packages:
+
+
+
+
+
+
+
+
+
+
+
+
+
+std: Core library modules
+
+
+
+
+
+
+std.windows: Modules specific to the Windows operating system
+
+
+
+
+
+
+std.linux: Modules specific to the Linux operating system
+
+
+std.c: Interface to C functions
+
+
+
+
+
+
+std.c.windows: Interface to C Windows functions
+
+
+
+
+
+
+std.c.linux: Interface to C Linux functions
+
+
+
+
+
+
+
+
+std.base64
+
+Encodes/decodes base64 data.
+
+
+std.compiler
+
+
+
+
+
+
+
+
+std.conv
+
+ std.conv provides basic building blocks for conversions from
+ strings to integral types. They differ from the C functions atoi()
+ and atol() by not allowing whitespace or overflows.
+
+ Integer:
+ Sign UnsignedInteger
+ UnsignedInteger
+
+ Sign:
+ +
+ -
+
+
+ For conversion to unsigned types, the grammar recognized is:
+
+
+ UnsignedInteger:
+ DecimalDigit
+ DecimalDigit UnsignedInteger
+
+
+ Any deviation from that grammar causes a ConvError exception
+ to be thrown. Any overflows cause a ConvOverflowError to
+ be thrown.
+
+
+
+
+
+
+std.ctype
+
+
+
+
+
+
+std.date
+
+ Dates are represented in several formats. The date implementation
+ revolves around a central type, d_time, from which other
+ formats are converted to and from.
+
+
+
+
+std.file
+
+
+
+
+
+
+std.gc
+
+ The garbage collector normally works behind the scenes without
+ needing any specific interaction. These functions are for
+ advanced applications that benefit from tuning the operation of the
+ collector.
+
+
+
+
+
+std.intrinsic
+
+ Intrinsic functions are functions built in to the compiler,
+ usually to take advantage of specific CPU features that
+ are inefficient to handle via external functions.
+ The compiler's optimizer and code generator are fully
+ integrated in with intrinsic functions, bringing to bear
+ their full power on them.
+ This can result in some surprising speedups.
+
+
+
+
+
+
+
+
+
+
+ import std.intrinsic;
+
+ int main()
+ {
+ uint v;
+ int x;
+
+ v = 0x21;
+ x = bsf(v);
+ printf("bsf(x%x) = %d\n", v, x);
+ x = bsr(v);
+ printf("bsr(x%x) = %d\n", v, x);
+ return 0;
+ }
+
+
+ bsf(x21) = 0
+ bsr(x21) = 5
+
+
+
+ p[index / (uint.size*8)] & (1 << (index & ((uint.size*8) - 1)))
+
+
+
+
+ import std.intrinsic;
+
+ int main()
+ {
+ uint array[2];
+
+ array[0] = 2;
+ array[1] = 0x100;
+
+ printf("btc(array, 35) = %d\n", btc(array, 35));
+ printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+ printf("btc(array, 35) = %d\n", btc(array, 35));
+ printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+ printf("bts(array, 35) = %d\n", bts(array, 35));
+ printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+ printf("btr(array, 35) = %d\n", btr(array, 35));
+ printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+ printf("bt(array, 1) = %d\n", bt(array, 1));
+ printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+ return 0;
+ }
+
+ btc(array, 35) = 0
+ array = [0]:x2, [1]:x108
+ btc(array, 35) = -1
+ array = [0]:x2, [1]:x100
+ bts(array, 35) = 0
+ array = [0]:x2, [1]:x108
+ btr(array, 35) = -1
+ array = [0]:x2, [1]:x100
+ bt(array, 1) = -1
+ array = [0]:x2, [1]:x100
+
+
+std.math
+
+
+
+
+
+
+ Special values:
+
+
+
+ x
+ return value
+ invalid?
+
+ ±INFINITY
+ NAN
+ yes
+
+ Special values:
+
+
+
+ x
+ return value
+ invalid?
+
+ ±0.0
+ ±0.0
+ no
+
+ ±INFINITY
+ NAN
+ yes
+
+ Special values:
+
+
+
+ x
+ return value
+ invalid?
+
+ ±0.0
+ ±0.0
+ no
+
+ ±INFINITY
+ NAN
+ yes
+
+ value=x*2exp
+ .5 <= |x| < 1.0
+ x has same sign as value.
+
+ Special values:
+
+
+
+ value x exp
+
+ +-0.0 +-0.0 0
+
+ +INFINITY +INFINITY int.max
+
+ -INFINITY -INFINITY int.min
+
+ +-NAN +-NAN int.min
+
+ Special values:
+
+
+
+ x return value divide by 0? invalid?
+
+ ±0.0 -INFINITY yes no
+
+ < 0.0 NAN no yes
+
+ +INFINITY +INFINITY no no
+
+ Special values:
+
+
+
+ x return value divide by 0? invalid?
+
+ ±0.0 -INFINITY yes no
+
+ < 0.0 NAN no yes
+
+ +INFINITY +INFINITY no no
+
+ Special values:
+
+
+
+ x
+ return value
+ invalid?
+
+ -0.0
+ -0.0
+ no
+
+ <0.0
+ NAN
+ yes
+
+ +INFINITY
+ +INFINITY
+ no
+
+ Special values:
+
+
+
+ x
+ log1p(x)
+ divide by 0?
+ invalid?
+
+ ±0.0
+ ±0.0
+ no
+ no
+
+ -1.0
+ -INFINITY
+ yes
+ no
+
+ <-1.0
+ NAN
+ no
+ yes
+
+ +INFINITY
+ -INFINITY
+ no
+ no
+
+ Special values:
+
+
+
+ x
+ ex-1
+
+ ±0.0
+ ±0.0
+
+ +INFINITY
+ +INFINITY
+
+ -INFINITY
+ -1.0
+
+ sqrt(x2 + y2)
+ Note that hypot(x,y), hypot(y,x) and
+ hypot(x,-y) are equivalent.
+ Special values:
+
+
+
+ x
+ y
+ return value
+ invalid?
+
+ x
+ +-0.0
+ fabs(x)
+ no
+
+ +-INFINITY
+ y
+ +INFINITY
+ no
+
+ +-INFINITY
+ NAN
+ +INFINITY
+ no
+
+std.md5
+
+Computes MD5 digests of arbitrary data. MD5 digests are 16 byte quantities
+that are like a checksum or crc, but are more robust.
+
+
+
+
+
+
+
+
+Example
+
+
+
+
+// This code is derived from the
+// RSA Data Security, Inc. MD5 Message-Digest Algorithm.
+
+import std.md5;
+import std.string;
+import std.c.stdio;
+
+int main(char[][] args)
+{
+ for (int i = 1; i < args.length; i++)
+ MDFile(args[i]);
+ return 0;
+}
+
+/* Digests a file and prints the result. */
+void MDFile(char[] filename)
+{
+ FILE* file;
+ MD5_CTX context;
+ int len;
+ ubyte [4 * 1024] buffer;
+ ubyte digest[16];
+
+ if ((file = fopen(std.string.toStringz(filename), "rb")) == null)
+ printf("%.*s can't be opened\n", filename);
+ else
+ {
+ context.start();
+ while ((len = fread(buffer, 1, buffer.size, file)) != 0)
+ context.update(buffer[0 .. len]);
+ context.finish(digest);
+ fclose(file);
+
+ printf("MD5 (%.*s) = ", filename);
+ printDigest(digest);
+ printf("\n");
+ }
+}
+
+object
+
+This module is implicitly imported.
+
+
+
+
+
+
+
+
+
+
+
+std.outbuffer
+
+
+
+
+
+
+
+
+
+std.path
+
+
+
+
+
+
+
+ Matching is case sensitive on a file system that is case sensitive.
+ Returns:
+
+
+
+std.process
+
+
+
+
+
+
+std.random
+
+
+
+
+
+
+std.socketstream
+
+
+
+
+
+
+
+
+
+
wchar[] readLineW()
+ Notes
+
+ For Win32 systems, link with ws2_32.lib.
+
+Example
+
+ See /dmd/samples/d/htmlget.d.
+
+
+std.stdint
+
+ D constrains integral types to specific sizes. But efficiency
+ of different sizes varies from machine to machine,
+ pointer sizes vary, and the maximum integer size varies.
+ stdint offers a portable way of trading off size
+ vs efficiency, in a manner compatible with the stdint.h
+ definitions in C.
+
+
+ Exact Alias
+ Description
+ At Least Alias
+ Description
+ Fast Alias
+ Description
+
+ int8_t
+ exactly 8 bits signed
+ int_least8_t
+ at least 8 bits signed
+ int_fast8_t
+ fast 8 bits signed
+
+ uint8_t
+ exactly 8 bits unsigned
+ uint_least8_t
+ at least 8 bits unsigned
+ uint_fast8_t
+ fast 8 bits unsigned
+
+
+ int16_t
+ exactly 16 bits signed
+ int_least16_t
+ at least 16 bits signed
+ int_fast16_t
+ fast 16 bits signed
+
+ uint16_t
+ exactly 16 bits unsigned
+ uint_least16_t
+ at least 16 bits unsigned
+ uint_fast16_t
+ fast 16 bits unsigned
+
+
+ int32_t
+ exactly 32 bits signed
+ int_least32_t
+ at least 32 bits signed
+ int_fast32_t
+ fast 32 bits signed
+
+ uint32_t
+ exactly 32 bits unsigned
+ uint_least32_t
+ at least 32 bits unsigned
+ uint_fast32_t
+ fast 32 bits unsigned
+
+
+ int64_t
+ exactly 64 bits signed
+ int_least64_t
+ at least 64 bits signed
+ int_fast64_t
+ fast 64 bits signed
+
+ uint64_t
+ exactly 64 bits unsigned
+ uint_least64_t
+ at least 64 bits unsigned
+ uint_fast64_t
+ fast 64 bits unsigned
+
+
+ Alias
+ Description
+
+ intptr_t
+ signed integral type large enough to hold a pointer
+
+ uintptr_t
+ unsigned integral type large enough to hold a pointer
+
+
+
+Alias
+ Description
+
+ intmax_t
+ the largest signed integral type
+
+ uintmax_t
+ the largest unsigned integral type
+
+std.stdio
+
+ Standard I/O functions that extend std.c.stdio.
+ std.c.stdio is automatically imported when importing
+ std.stdio.
+
+
+
+
+
+std.stream
+
+
+
+
+
+
+
+
+
+
+
void read(out ubyte x)
+
void read(out short x)
+
void read(out ushort x)
+
void read(out int x)
+
void read(out uint x)
+
void read(out long x)
+
void read(out ulong x)
+
void read(out float x)
+
void read(out double x)
+
void read(out real x)
+
void read(out ifloat x)
+
void read(out idouble x)
+
void read(out ireal x)
+
void read(out cfloat x)
+
void read(out cdouble x)
+
void read(out creal x)
+
void read(out char x)
+
void read(out wchar x)
+
void read(out dchar x)
+
void read(out char[] s)
+
void read(out wchar[] s)
+
wchar[] readLineW()
+
wchar[] readLineW(wchar[] buffer)
+
wchar getcw()
+
wchar ungetcw(wchar c)
+
int vscanf(char[] fmt, va_list args)
+
+
+
+
+
+
void write(ubyte x)
+
void write(short x)
+
void write(ushort x)
+
void write(int x)
+
void write(uint x)
+
void write(long x)
+
void write(ulong x)
+
void write(float x)
+
void write(double x)
+
void write(real x)
+
void write(ifloat x)
+
void write(idouble x)
+
void write(ireal x)
+
void write(cfloat x)
+
void write(cdouble x)
+
void write(creal x)
+
void write(char x)
+
void write(wchar x)
+
void write(dchar x)
+
void write(char[] s)
+
void write(wchar[] s)
+
+
+
+
+ Reading
+ Writing
+ Seeking
+ seek(0, SeekPos.Current)
or
+ seek(pos, SeekPos.Set)
respectively.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+std.system
+
+
+
+
+
+
+
+
+std.thread
+
+ The thread module defines the class Thread.
+ Thread is the basis
+ for writing multithreaded applications. Each thread
+ has a unique instance of class Thread associated with it.
+ It is important to use the Thread class to create and manage
+ threads as the garbage collector needs to know about all the threads.
+
+
+
+ The members of Thread are:
+
+
+
+
+
+
+
+ TS
+ Description
+
+ INITIAL
+ The thread hasn't been started yet.
+
+ RUNNING
+ The thread is running or paused.
+
+ TERMINATED
+ The thread has ended.
+
+
+
+ PRIORITY
+ Description
+
+ INCREASE
+ Increase thread priority
+
+ DECREASE
+ Decrease thread priority
+
+ IDLE
+ Assign thread low priority
+
+ CRITICAL
+ Assign thread high priority
+
+std.uri
+
+ Encode and decode Uniform Resource Identifiers (URIs).
+ URIs are used in internet transfer protocols.
+ Valid URI characters consist of letters, digits, and
+ the characters ;/?:@&=+$,-_.!~*'(). Escape sequences
+ consist of '%' followed by two hex digits.
+
+
+
+
+
+std.utf
+
+ Encode and decode UTF-8, UTF-16 and UTF-32 strings.
+ For more information on UTF-8, see
+ http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8.
+
+
+
+
+
+
+std.zip
+
+ Read/write data in the zip archive format.
+ Makes use of the zlib compression library.
+
+
+
+ Bugs:
+
+
+
+
+
+
+ ZipArchive archive = new ZipArchive(data);
+foreach (ArchiveMember am; archive)
+{
+ printf("member name is '%.*s'\n", am.name);
+}
+
+
+
+
+
+
+std.zlib
+
+ Compress / decompress data using the
+ zlib library.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+std.c.stdio
+
+
+
+
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last modified Mar 22, 2004.
-
-
-Portability Guide
-
- It's good software engineering practice to minimize gratuitous
- portability problems in the code.
- Techniques to minimize potential portability problems are:
-
-
-
-
-
-
- a + b + c
-
-
- can be evaluated as (a + b) + c, a + (b + c), (a + c) + b, (c + b) + a,
- etc. Parenthesis control operator precedence, parenthesis do not
- control order of evaluation.
-
- assert(int.size == (int*).size);
-
-
- 32 to 64 Bit Portability
-
- 64 bit processors and operating systems are coming.
- With that in mind:
-
-
-
-
-
-OS Specific Code
-
- System specific code is handled by isolating the differences into
- separate modules. At compile time, the correct system specific
- module is imported.
- Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright (c) 1999-2004 by Digital Mars, All Rights Reserved
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Last update Thu May 19 2005
+
+
+
+Portability Guide
+
+ It's good software engineering practice to minimize gratuitous
+ portability problems in the code.
+ Techniques to minimize potential portability problems are:
+
+
+
+
+
+
+ a + b + c
+
+
+ can be evaluated as (a + b) + c, a + (b + c), (a + c) + b, (c + b) + a,
+ etc. Parenthesis control operator precedence, parenthesis do not
+ control order of evaluation.
+
+ assert(int.size == (int*).size);
+
+
+ 32 to 64 Bit Portability
+
+ 64 bit processors and operating systems are coming.
+ With that in mind:
+
+
+
+
+
+OS Specific Code
+
+ System specific code is handled by isolating the differences into
+ separate modules. At compile time, the correct system specific
+ module is imported.
+ Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last modified Mar 8, 2005.
-
-
-Pragmas
-
-
- Pragma:
- pragma ( Identifier )
- pragma ( Identifier , ExpressionList )
-
-
-
- Pragmas are a way to pass special information to the compiler
- and to add vendor specific extensions to D.
- Pragmas can be used by themselves terminated with a ';',
- they can influence a statement, a block of statements, a declaration, or
- a block of declarations.
-
-
- pragma(ident); // just by itself
-
- pragma(ident) declaration; // influence one declaration
-
- pragma(ident): // influence subsequent declarations
- declaration;
- declaration;
-
- pragma(ident) // influence block of declarations
- { declaration;
- declaration;
- }
-
- pragma(ident) statement; // influence one statement
-
- pragma(ident) // influence block of statements
- { statement;
- statement;
- }
-
-
- The kind of pragma it is is determined by the Identifier.
- ExpressionList is a comma-separated list of
- AssignExpressions. The AssignExpressions must be
- parsable as expressions, but what they mean semantically
- is up to the individual pragma semantics.
-
-Predefined Pragmas
-
- All implementations must support these, even if by just ignoring
- them:
-
-
-
-
-
-
- pragma(msg, "compiling...");
-
-
- pragma(lib, "foo.lib");
-
-
- Vendor Specific Pragmas
-
- Vendor specific pragma Identifiers can be defined if they
- are prefixed by the vendor's trademarked name, in a similar manner
- to version identifiers:
-
-
- pragma(DigitalMars_funky_extension) { ... }
-
-
- Compilers must diagnose an error for unrecognized Pragmas,
- even if they are vendor specific ones. This implies that vendor
- specific pragmas should be wrapped in version statements:
-
-
- version (DigitalMars)
- {
- pragma(DigitalMars_funky_extension) { ... }
- }
-
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 2003-2005 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+
+Pragmas
+
+
+
+
+ Pragma:
+ pragma ( Identifier )
+ pragma ( Identifier , ExpressionList )
+
+
+
+ pragma(ident); // just by itself
+
+ pragma(ident) declaration; // influence one declaration
+
+ pragma(ident): // influence subsequent declarations
+ declaration;
+ declaration;
+
+ pragma(ident) // influence block of declarations
+ { declaration;
+ declaration;
+ }
+
+ pragma(ident) statement; // influence one statement
+
+ pragma(ident) // influence block of statements
+ { statement;
+ statement;
+ }
+
Predefined Pragmas
+
+ All implementations must support these, even if by just ignoring
+ them:
+
+
+
+
+
+
+
+
+ pragma(msg, "compiling...");
+
+
+ pragma(lib, "foo.lib");
Vendor Specific Pragmas
+
+ Vendor specific pragma Identifiers can be defined if they
+ are prefixed by the vendor's trademarked name, in a similar manner
+ to version identifiers:
+
+
+
+
+ pragma(DigitalMars_funky_extension) { ... }
+
+
+
+ version (DigitalMars)
+ {
+ pragma(DigitalMars_funky_extension) { ... }
+ }
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last update May 21, 2004
-
-
-The C Preprocessor Versus D
-
- Back when C was invented, compiler technology was primitive.
- Installing a text
- macro preprocessor onto the front end was a straightforward
- and easy way to add many
- powerful features. The increasing size & complexity of programs
- have illustrated
- that these features come with many inherent problems.
- D doesn't have a preprocessor; but
- D provides a more scalable means to solve the same problems.
-
-
-
-
-
-Header Files
-
-The C Preprocessor Way
-
- C and C++ rely heavilly on textual inclusion of header files.
- This frequently results in the compiler having to recompile tens of thousands
- of lines of code over and over again for every source file, an obvious
- source of slow compile times. What header files are normally used for is
- more appropriately done doing a symbolic, rather than textual, insertion.
- This is done with the import statement. Symbolic inclusion means the compiler
- just loads an already compiled symbol table. The needs for macro "wrappers" to
- prevent multiple #inclusion, funky #pragma once syntax, and incomprehensible
- fragile syntax for precompiled headers are simply unnecessary and irrelevant to
- D.
-
-
- #include <stdio.h>
-
-
-The D Way
-
- D uses symbolic imports:
-
-
- import std.c.stdio;
-
-
-
-#pragma once
-
-The C Preprocessor Way
-
- C header files frequently need to be protected against
- being #include'd multiple times.
- To do it, a header file will contain the line:
-
- #pragma once
-
-
- or the more portable:
-
-
- #ifndef __STDIO_INCLUDE
- #define __STDIO_INCLUDE
- ... header file contents
- #endif
-
-
-The D Way
-
- Completely unnecessary since D does a symbolic include of import
- files; they only get imported once no matter how many times
- the import declaration appears.
-
-
-#pragma pack
-
-The C Preprocessor Way
-
- This is used in C to adjust the alignment for structs.
-
-The D Way
-
- For D classes, there is no
- need to adjust the alignment (in fact, the compiler is free to rearrange the data
- fields to get the optimum layout, much as the compiler will rearrange local
- variables on the stack frame). For D structs
- that get mapped onto externally defined data structures, there is a need, and
- it is handled with:
-
-
- struct Foo
- {
- align (4): // use 4 byte alignment
- ...
- }
-
-
-
-Macros
-
- Preprocessor macros add powerful features and flexibility to C. But they have a
- downside:
-
-
-
-
-
- Here's an enumeration of the common uses for macros, and the corresponding
- feature in D:
-
-
-
-The C Preprocessor Way
-
-
- #define VALUE 5
-
-
- The D Way
-
-
- const int VALUE = 5;
-
-
- The C Preprocessor Way
-
-
- int flags:
- #define FLAG_X 0x1
- #define FLAG_Y 0x2
- #define FLAG_Z 0x4
- ...
- flags |= FLAG_X;
-
-
- The D Way
-
-
- enum FLAGS { X = 0x1, Y = 0x2, Z = 0x4 };
- FLAGS flags;
- ...
- flags |= FLAGS.X;
-
-
- The C Preprocessor Way
-
-
- #if UNICODE
- #define dchar wchar_t
- #define TEXT(s) L##s
- #else
- #define dchar char
- #define TEXT(s) s
- #endif
-
- ...
- dchar h[] = TEXT("hello");
-
-
- The D Way
-
-
- dchar[] h = "hello";
-
-
-
- D's optimizer will inline the function, and will do the conversion of the
- string constant at compile time.
- The C Preprocessor Way
-
-
- #if PROTOTYPES
- #define P(p) p
- #else
- #define P(p) ()
- #endif
- int func P((int x, int y));
-
-
- The D Way
-
- By making the D compiler open source, it will largely
- avoid the problem of syntactical backwards compatibility.
-
- The C Preprocessor Way
-
-
- #define INT int
-
-
- The D Way
-
-
- alias int INT;
-
-
- The C Preprocessor Way
-
-
- #define EXTERN extern
- #include "declations.h"
- #undef EXTERN
- #define EXTERN
- #include "declations.h"
-
-
- In declarations.h:
-
-
- EXTERN int foo;
-
-
-
- The D Way
-
- The declaration and the definition are the same, so there is no need
- to muck with the storage class to generate both a declaration and a definition
- from the same source.
-
- The C Preprocessor Way
-
-
- #define X(i) ((i) = (i) / 3)
-
-
- The D Way
-
-
- int X(inout int i) { return i = i / 3; }
-
-
- The compiler optimizer will inline it; no efficiency is lost.
-
- The C Preprocessor Way
-
-
- #define assert(e) ((e) || _assert(__LINE__, __FILE__))
-
-
- The D Way
-
- assert() is a built-in expression primitive. Giving the compiler
- such knowledge of assert() also enables the optimizer to know about things
- like the _assert() function never returns.
-
- The C Preprocessor Way
-
-
- #ifndef _CRTAPI1
- #define _CRTAPI1 __cdecl
- #endif
- #ifndef _CRTAPI2
- #define _CRTAPI2 __cdecl
- #endif
-
- int _CRTAPI2 func();
-
-
- The D Way
-
- Calling conventions can be specified in blocks, so there's no
- need to change it for every function:
-
-
- extern (Windows)
- {
- int onefunc();
- int anotherfunc();
- }
-
-
- The C Preprocessor Way
-
-
- #define LPSTR char FAR *
-
-
- The D Way
-
- D doesn't support 16 bit code, mixed pointer sizes, and different
- kinds of pointers, and so the problem is just
- irrelevant.
-
- The C Preprocessor Way
-
- Selecting which function to use based on text substitution:
-
-
- #ifdef UNICODE
- int getValueW(wchar_t *p);
- #define getValue getValueW
- #else
- int getValueA(char *p);
- #define getValue getValueA
- #endif
-
-
- The D Way
-
- D enables declarations of symbols that are aliases of
- other symbols:
-
-
- version (UNICODE)
- {
- int getValueW(wchar[] p);
- alias getValueW getValue;
- }
- else
- {
- int getValueA(char[] p);
- alias getValueA getValue;
- }
-
-
-Conditional Compilation
-
-
-The C Preprocessor Way
-
- Conditional compilation is a powerful feature of the C preprocessor,
- but it has its downside:
-
-
-
-
-The D Way
-
- D supports conditional compilation:
-
-
-
-
-
-Code Factoring
-
-The C Preprocessor Way
-
- It's common in a function to have a repetitive sequence
- of code to be executed in multiple places. Performance
- considerations preclude factoring it out into a separate
- function, so it is implemented as a macro. For example,
- consider this fragment from a byte code interpreter:
-
-
- unsigned char *ip; // byte code instruction pointer
- int *stack;
- int spi; // stack pointer
- ...
- #define pop() (stack[--spi])
- #define push(i) (stack[spi++] = (i))
- while (1)
- {
- switch (*ip++)
- {
- case ADD:
- op1 = pop();
- op2 = pop();
- result = op1 + op2;
- push(result);
- break;
-
- case SUB:
- ...
- }
- }
-
-
- This suffers from numerous problems:
-
-
-
-The D Way
-
- D neatly addresses this with nested functions:
-
-
- ubyte* ip; // byte code instruction pointer
- int[] stack; // operand stack
- int spi; // stack pointer
- ...
-
- int pop() { return stack[--spi]; }
- void push(int i) { stack[spi++] = i; }
-
- while (1)
- {
- switch (*ip++)
- {
- case ADD:
- op1 = pop();
- op2 = pop();
- push(op1 + op2);
- break;
-
- case SUB:
- ...
- }
- }
-
-
- The problems addressed are:
-
-
-
- Additionally, nested functions can be inlined by the implementation
- resulting in the same high performance that the C macro version
- exhibits.
-
-
-#error and Static Asserts
-
- Static asserts are user defined checks made at compile time;
- if the check fails the compile issues an error and fails.
-
-The C Preprocessor Way
-
- The first way is to use the #error preprocessing directive:
-
-
- #if FOO || BAR
- ... code to compile ...
- #else
- #error "there must be either FOO or BAR"
- #endif
-
-
- This has the limitations inherent in preprocessor expressions
- (i.e. integer constant expressions only, no casts, no sizeof,
- no symbolic constants, etc.).
-
- #define static_assert(_x) do { typedef int ai[(_x) ? 1 : 0]; } while(0)
-
-
- and using it like:
-
-
- void foo(T t)
- {
- static_assert(sizeof(T) < 4);
- ...
- }
-
-
- This works by causing a compile time semantic error if the condition
- evaluates
- to false. The limitations of this technique are a sometimes very
- confusing error message from the compiler, along with an inability
- to use a static_assert outside of a function body.
-
-The D Way
-
- D has the static assert,
- which can be used anywhere a declaration
- or a statement can be used. For example:
-
-
- version (FOO)
- {
- class Bar
- {
- const int x = 5;
- static assert(Bar.x == 5 || Bar.x == 6);
-
- void foo(T t)
- {
- static assert(T.size < 4);
- ...
- }
- }
- }
- else version (BAR)
- {
- ...
- }
- else
- {
- static assert(0); // unsupported version
- }
-
-
-
-Mixins
-
- D mixins superficially look just
- like using C's preprocessor to insert blocks of code and
- parse them in the scope of where they are instantiated.
- But the advantages of mixins over macros are:
-
-
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
-
Copyright (c) 1999-2004 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+The C Preprocessor Versus D
+
+ Back when C was invented, compiler technology was primitive.
+ Installing a text
+ macro preprocessor onto the front end was a straightforward
+ and easy way to add many
+ powerful features. The increasing size & complexity of programs
+ have illustrated
+ that these features come with many inherent problems.
+ D doesn't have a preprocessor; but
+ D provides a more scalable means to solve the same problems.
+
+
+
+
+
+Header Files
+
+The C Preprocessor Way
+
+ C and C++ rely heavilly on textual inclusion of header files.
+ This frequently results in the compiler having to recompile tens of thousands
+ of lines of code over and over again for every source file, an obvious
+ source of slow compile times. What header files are normally used for is
+ more appropriately done doing a symbolic, rather than textual, insertion.
+ This is done with the import statement. Symbolic inclusion means the compiler
+ just loads an already compiled symbol table. The needs for macro "wrappers" to
+ prevent multiple #inclusion, funky #pragma once syntax, and incomprehensible
+ fragile syntax for precompiled headers are simply unnecessary and irrelevant to
+ D.
+
+
+
+
+ #include <stdio.h>
+
The D Way
+
+ D uses symbolic imports:
+
+
+
+
+ import std.c.stdio;
+
+#pragma once
+
+The C Preprocessor Way
+
+ C header files frequently need to be protected against
+ being #include'd multiple times.
+ To do it, a header file will contain the line:
+
+
+
+ #pragma once
+
+
+
+ #ifndef __STDIO_INCLUDE
+ #define __STDIO_INCLUDE
+ ... header file contents
+ #endif
+
The D Way
+
+ Completely unnecessary since D does a symbolic include of import
+ files; they only get imported once no matter how many times
+ the import declaration appears.
+
+
+#pragma pack
+
+The C Preprocessor Way
+
+ This is used in C to adjust the alignment for structs.
+
+The D Way
+
+ For D classes, there is no
+ need to adjust the alignment (in fact, the compiler is free to rearrange the data
+ fields to get the optimum layout, much as the compiler will rearrange local
+ variables on the stack frame). For D structs
+ that get mapped onto externally defined data structures, there is a need, and
+ it is handled with:
+
+
+
+
+ struct Foo
+ {
+ align (4): // use 4 byte alignment
+ ...
+ }
+
+Macros
+
+ Preprocessor macros add powerful features and flexibility to C. But they have a
+ downside:
+
+
+
+
+
+ Here's an enumeration of the common uses for macros, and the corresponding
+ feature in D:
+
+
+
+The C Preprocessor Way
+
+
+
+
+ #define VALUE 5
+
The D Way
+
+
+
+
+ const int VALUE = 5;
+
The C Preprocessor Way
+
+
+
+
+ int flags:
+ #define FLAG_X 0x1
+ #define FLAG_Y 0x2
+ #define FLAG_Z 0x4
+ ...
+ flags |= FLAG_X;
+
The D Way
+
+
+
+
+ enum FLAGS { X = 0x1, Y = 0x2, Z = 0x4 };
+ FLAGS flags;
+ ...
+ flags |= FLAGS.X;
+
The C Preprocessor Way
+
+
+
+
+ #if UNICODE
+ #define dchar wchar_t
+ #define TEXT(s) L##s
+ #else
+ #define dchar char
+ #define TEXT(s) s
+ #endif
+
+ ...
+ dchar h[] = TEXT("hello");
+
The D Way
+
+
+
+
+ dchar[] h = "hello";
+
The C Preprocessor Way
+
+
+
+
+ #if PROTOTYPES
+ #define P(p) p
+ #else
+ #define P(p) ()
+ #endif
+ int func P((int x, int y));
+
The D Way
+
+ By making the D compiler open source, it will largely
+ avoid the problem of syntactical backwards compatibility.
+
+ The C Preprocessor Way
+
+
+
+
+ #define INT int
+
The D Way
+
+
+
+
+ alias int INT;
+
The C Preprocessor Way
+
+
+
+
+ #define EXTERN extern
+ #include "declations.h"
+ #undef EXTERN
+ #define EXTERN
+ #include "declations.h"
+
+
+
+ EXTERN int foo;
+
The D Way
+
+ The declaration and the definition are the same, so there is no need
+ to muck with the storage class to generate both a declaration and a definition
+ from the same source.
+
+ The C Preprocessor Way
+
+
+
+
+ #define X(i) ((i) = (i) / 3)
+
The D Way
+
+
+
+
+ int X(inout int i) { return i = i / 3; }
+
The C Preprocessor Way
+
+
+
+
+ #define assert(e) ((e) || _assert(__LINE__, __FILE__))
+
The D Way
+
+ assert() is a built-in expression primitive. Giving the compiler
+ such knowledge of assert() also enables the optimizer to know about things
+ like the _assert() function never returns.
+
+ The C Preprocessor Way
+
+
+
+
+ #ifndef _CRTAPI1
+ #define _CRTAPI1 __cdecl
+ #endif
+ #ifndef _CRTAPI2
+ #define _CRTAPI2 __cdecl
+ #endif
+
+ int _CRTAPI2 func();
+
The D Way
+
+ Calling conventions can be specified in blocks, so there's no
+ need to change it for every function:
+
+
+
+
+ extern (Windows)
+ {
+ int onefunc();
+ int anotherfunc();
+ }
+
The C Preprocessor Way
+
+
+
+
+ #define LPSTR char FAR *
+
The D Way
+
+ D doesn't support 16 bit code, mixed pointer sizes, and different
+ kinds of pointers, and so the problem is just
+ irrelevant.
+
+ The C Preprocessor Way
+
+ Selecting which function to use based on text substitution:
+
+
+
+
+ #ifdef UNICODE
+ int getValueW(wchar_t *p);
+ #define getValue getValueW
+ #else
+ int getValueA(char *p);
+ #define getValue getValueA
+ #endif
+
The D Way
+
+ D enables declarations of symbols that are aliases of
+ other symbols:
+
+
+
+
+ version (UNICODE)
+ {
+ int getValueW(wchar[] p);
+ alias getValueW getValue;
+ }
+ else
+ {
+ int getValueA(char[] p);
+ alias getValueA getValue;
+ }
+
+Conditional Compilation
+
+
+The C Preprocessor Way
+
+ Conditional compilation is a powerful feature of the C preprocessor,
+ but it has its downside:
+
+
+
+
+The D Way
+
+ D supports conditional compilation:
+
+
+
+
+
+Code Factoring
+
+The C Preprocessor Way
+
+ It's common in a function to have a repetitive sequence
+ of code to be executed in multiple places. Performance
+ considerations preclude factoring it out into a separate
+ function, so it is implemented as a macro. For example,
+ consider this fragment from a byte code interpreter:
+
+
+
+
+ unsigned char *ip; // byte code instruction pointer
+ int *stack;
+ int spi; // stack pointer
+ ...
+ #define pop() (stack[--spi])
+ #define push(i) (stack[spi++] = (i))
+ while (1)
+ {
+ switch (*ip++)
+ {
+ case ADD:
+ op1 = pop();
+ op2 = pop();
+ result = op1 + op2;
+ push(result);
+ break;
+
+ case SUB:
+ ...
+ }
+ }
+
+
+
+The D Way
+
+ D neatly addresses this with nested functions:
+
+
+
+
+ ubyte* ip; // byte code instruction pointer
+ int[] stack; // operand stack
+ int spi; // stack pointer
+ ...
+
+ int pop() { return stack[--spi]; }
+ void push(int i) { stack[spi++] = i; }
+
+ while (1)
+ {
+ switch (*ip++)
+ {
+ case ADD:
+ op1 = pop();
+ op2 = pop();
+ push(op1 + op2);
+ break;
+
+ case SUB:
+ ...
+ }
+ }
+
+
+
+ Additionally, nested functions can be inlined by the implementation
+ resulting in the same high performance that the C macro version
+ exhibits.
+
+
+#error and Static Asserts
+
+ Static asserts are user defined checks made at compile time;
+ if the check fails the compile issues an error and fails.
+
+The C Preprocessor Way
+
+ The first way is to use the #error preprocessing directive:
+
+
+
+
+ #if FOO || BAR
+ ... code to compile ...
+ #else
+ #error "there must be either FOO or BAR"
+ #endif
+
+
+
+ #define static_assert(_x) do { typedef int ai[(_x) ? 1 : 0]; } while(0)
+
+
+
+ void foo(T t)
+ {
+ static_assert(sizeof(T) < 4);
+ ...
+ }
+
The D Way
+
+ D has the static assert,
+ which can be used anywhere a declaration
+ or a statement can be used. For example:
+
+
+
+
+ version (FOO)
+ {
+ class Bar
+ {
+ const int x = 5;
+ static assert(Bar.x == 5 || Bar.x == 6);
+
+ void foo(T t)
+ {
+ static assert(T.size < 4);
+ ...
+ }
+ }
+ }
+ else version (BAR)
+ {
+ ...
+ }
+ else
+ {
+ static assert(0); // unsupported version
+ }
+
+Mixins
+
+ D mixins superficially look just
+ like using C's preprocessor to insert blocks of code and
+ parse them in the scope of where they are instantiated.
+ But the advantages of mixins over macros are:
+
+
+
+
+Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-
-Properties
-
- Every type and expression has properties that can be queried:
-
-
- int.sizeof yields 4
- float.nan yields the floating point nan (Not A Number) value
- (float).nan yields the floating point nan value
- (3).sizeof yields 4 (because 3 is an int)
- 2.sizeof syntax error, since "2." is a floating point number
- int.init default initializer for int's
-
-
-
-Properties for Integral Data Types
-
-
- .init initializer (0)
- .sizeof size in bytes (equivalent to C's sizeof(type))
- .alignof alignment size
- .max maximum value
- .min minimum value
-
-
-Properties for Floating Point Types
-
-
- .init initializer (NaN)
- .sizeof size in bytes (equivalent to C's sizeof(type))
- .alignof alignment size
- .infinity infinity value
- .nan NaN value
- .dig number of decimal digits of precision
- .epsilon smallest increment
- .mant_dig number of bits in mantissa
- .max_10_exp maximum exponent as power of 10
- .max_exp maximum exponent as power of 2
- .min_10_exp minimum exponent as power of 10
- .min_exp minimum exponent as power of 2
- .max largest representable value that's not infinity
- .min smallest representable value that's not 0
-
-
-.init Property
-
- .init produces a constant expression that is the default
- initializer. If applied to a type, it is the default initializer
- for that type. If applied to a variable or field, it is the
- default initializer for that variable or field.
- For example:
-
-
-
- int a;
- int b = 1;
- typedef int t = 2;
- t c;
- t d = cast(t)3;
-
- int.init // is 0
- a.init // is 0
- b.init // is 1
- t.init // is 2
- c.init // is 2
- d.init // is 3
-
- struct Foo
- {
- int a;
- int b = 7;
- }
-
- Foo.a.init // is 0
- Foo.b.init // is 7
-
-
-Class and Struct Properties
-
- Properties are member functions that can by syntactically treated
- as if they were fields. Properties can be read from or written to.
- A property is read by calling a method with no arguments;
- a property is written by calling a method with its argument
- being the value it is set to.
-
- struct Foo
- {
- int data() { return m_data; } // read property
-
- int data(int value) { return m_data = value; } // write property
-
- private:
- int m_data;
- }
-
-
- To use it:
-
-
- int test()
- {
- Foo f;
-
- f.data = 3; // same as f.data(3);
- return f.data + 3; // same as return f.data() + 3;
- }
-
-
- The absence of a read method means that the property is write-only.
- The absence of a write method means that the property is read-only.
- Multiple write methods can exist; the correct one is selected using
- the usual function overloading rules.
- Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+Properties
+
+ Every type and expression has properties that can be queried:
+
+
+ int.sizeof yields 4
+ float.nan yields the floating point nan (Not A Number) value
+ (float).nan yields the floating point nan value
+ (3).sizeof yields 4 (because 3 is an int)
+ 2.sizeof syntax error, since "2." is a floating point number
+ int.init default initializer for int's
+
+
+
+Properties for Integral Data Types
+
+
+ .init initializer (0)
+ .sizeof size in bytes (equivalent to C's sizeof(type))
+ .alignof alignment size
+ .max maximum value
+ .min minimum value
+
+
+Properties for Floating Point Types
+
+
+ .init initializer (NaN)
+ .sizeof size in bytes (equivalent to C's sizeof(type))
+ .alignof alignment size
+ .infinity infinity value
+ .nan NaN value
+ .dig number of decimal digits of precision
+ .epsilon smallest increment
+ .mant_dig number of bits in mantissa
+ .max_10_exp maximum exponent as power of 10
+ .max_exp maximum exponent as power of 2
+ .min_10_exp minimum exponent as power of 10
+ .min_exp minimum exponent as power of 2
+ .max largest representable value that's not infinity
+ .min smallest representable value that's not 0
+
+
+.init Property
+
+ .init produces a constant expression that is the default
+ initializer. If applied to a type, it is the default initializer
+ for that type. If applied to a variable or field, it is the
+ default initializer for that variable or field.
+ For example:
+
+
+
+
+ int a;
+ int b = 1;
+ typedef int t = 2;
+ t c;
+ t d = cast(t)3;
+
+ int.init // is 0
+ a.init // is 0
+ b.init // is 1
+ t.init // is 2
+ c.init // is 2
+ d.init // is 3
+
+ struct Foo
+ {
+ int a;
+ int b = 7;
+ }
+
+ Foo.a.init // is 0
+ Foo.b.init // is 7
+
Class and Struct Properties
+
+ Properties are member functions that can by syntactically treated
+ as if they were fields. Properties can be read from or written to.
+ A property is read by calling a method with no arguments;
+ a property is written by calling a method with its argument
+ being the value it is set to.
+
+
+
+ struct Foo
+ {
+ int data() { return m_data; } // read property
+
+ int data(int value) { return m_data = value; } // write property
+
+ private:
+ int m_data;
+ }
+
+
+
+ int test()
+ {
+ Foo f;
+
+ f.data = 3; // same as f.data(3);
+ return f.data + 3; // same as return f.data() + 3;
+ }
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last modified Mar 17, 2005.
-
-
-Statements
-
-C and C++ programmers will find the D statements very familiar, with a few
-interesting additions.
-
-
- Statement:
- LabeledStatement
- BlockStatement
- ExpressionStatement
- DeclarationStatement
- IfStatement
- DebugStatement
- VersionStatement
- WhileStatement
- DoWhileStatement
- ForStatement
- ForeachStatement
- SwitchStatement
- CaseStatement
- DefaultStatement
- ContinueStatement
- BreakStatement
- ReturnStatement
- GotoStatement
- WithStatement
- SynchronizeStatement
- TryStatement
- ThrowStatement
- VolatileStatement
- AsmStatement
- PragmaStatement
-
-
-Labelled Statements
-
- Statements can be labelled. A label is an identifier that
- precedes a statement.
-
-
- LabelledStatement:
- Identifier ':' Statement
-
-
- Any statement can be labelled, including empty statements,
- and so can serve as the target
- of a goto statement. Labelled statements can also serve as the
- target of a break or continue statement.
- Block Statement
-
- A block statement is a sequence of statements enclosed
- by { }. The statements are executed in lexical order.
-
-
- BlockStatement:
- { }
- { StatementList }
-
- StatementList:
- Statement
- Statement StatementList
-
-
- A block statement introduces a new scope for local
- symbols. A local symbol's name, however, must be unique within
- the function.
-
-
- void func1(int x)
- { int x; // illegal, x is multiply defined in function scope
- }
-
- void func2()
- {
- int x;
-
- { int x; // illegal, x is multiply defined in function scope
- }
- }
-
- void func3()
- {
- { int x;
- }
- { int x; // illegal, x is multiply defined in function scope
- }
- }
-
- void func4()
- {
- { int x;
- }
- { x++; // illegal, x is undefined
- }
- }
-
-
- The idea is to avoid bugs in complex functions caused by
- scoped declarations inadvertantly hiding previous ones.
- Local names should all be unique within a function.
-
-Expression Statement
-
- The expression is evaluated.
-
-
- ExpressionStatement:
- Expression ;
-
-
- Expressions that have no effect, like (x + x), are illegal
- in expression statements.
-
-Declaration Statement
-
- Declaration statements declare and initialize variables.
-
-
- DeclarationStatement:
- Type IdentifierList ;
-
- IdentifierList:
- Variable
- Variable , IdentifierList
-
- Variable:
- Identifier
- Identifier = AssignmentExpression
-
-
- If no AssignmentExpression is there to initialize the
- variable, it is initialized to the default value for its type.
-
-If Statement
-
- If statements provide simple conditional execution of statements.
-
-
- IfStatement:
- if ( Expression ) Statement
- if ( Expression ) Statement else Statement
-
-
- Expression is evaluated and must have a type that
- can be converted to a boolean. If it's true the if
- statement is transferred to, else the else statement
- is transferred to.
- While Statement
-
- While statements implement simple loops.
-
-
- WhileStatement:
- while ( Expression ) Statement
-
-
- Expression is evaluated and must have a type that
- can be converted to a boolean. If it's true the
- statement is executed. After the statement is executed,
- the Expression is evaluated again, and if true the
- statement is executed again. This continues until the
- Expression evaluates to false.
- Do-While Statement
-
- Do-While statements implement simple loops.
-
-
- DoStatement:
- do Statement while ( Expression )
-
-
- Statement is executed. Then
- Expression is evaluated and must have a type that
- can be converted to a boolean. If it's true the
- loop is iterated again.
- This continues until the
- Expression evaluates to false.
- For Statement
-
- For statements implement loops with initialization,
- test, and increment clauses.
-
-
- ForStatement:
- for (Initialize; Test; Increment) Statement
-
- Initialize:
- empty
- Expression
- Declaration
-
- Test:
- empty
- Expression
-
- Increment:
- empty
- Expression
-
-
- Initializer is executed.
- Test is evaluated and must have a type that
- can be converted to a boolean. If it's true the
- statement is executed. After the statement is executed,
- the Increment is executed.
- Then Test is evaluated again, and if true the
- statement is executed again. This continues until the
- Test evaluates to false.
-
- for (int i = 0; i < 10; i++)
- foo(i);
-
-
- is equivalent to:
-
-
- { int i;
- for (i = 0; i < 10; i++)
- foo(i);
- }
-
-
- Function bodies cannot be empty:
-
-
- for (int i = 0; i < 10; i++)
- ; // illegal
-
-
- Use instead:
-
-
- for (int i = 0; i < 10; i++)
- {
- }
-
-
- The Initializer may be omitted. Test may also be
- omitted, and if so, it is treated as if it evaluated to true.
-
-Foreach Statement
-
- A foreach statement loops over the contents of an aggregate.
-
-
- ForeachStatement:
- foreach (ForeachTypeList; Expression) Statement
-
- ForeachTypeList:
- ForeachType
- ForeachType , ForeachTypeList
-
- ForeachType:
- inout Type Identifier
- Type Identifier
-
-
- Expression is evaluated. It must evaluate to an aggregate
- expression
- of type static array, dynamic array, associative array,
- struct, or class.
- The Statement is executed, once for each element of the
- aggregate expression.
- At the start of each iteration, the variables declared by
- the ForeachTypeList
- are set to be a copy of the contents of the aggregate.
- If the variable is inout, it is a reference to the
- contents of that aggregate.
-
- char[] a;
- ...
- foreach (int i, char c; a)
- {
- printf("a[%d] = '%c'\n", i, c);
- }
-
-
- If the aggregate expression is a static or dynamic array of
- chars, wchars, or dchars, then the Type of
- the value
- can be any of char, wchar, or dchar.
- In this manner any UTF array
- can be decoded into any UTF type:
-
-
- char[] a = "\xE2\x89\xA0"; // \u2260 encoded as 3 UTF-8 bytes
-
- foreach (dchar c; a)
- {
- printf("a[] = %x\n", c); // prints 'a[] = 2260'
- }
-
- dchar[] b = "\u2260";
-
- foreach (char c; b)
- {
- printf("%x, ", c); // prints 'e2, 89, a0'
- }
-
-
-
- If the aggregate expression is an associative array, there
- can be one or two variables declared. If one, then the variable
- is said to be the value set to the elements of the array,
- one by one. The type of the
- variable must match the type of the array contents. If there are
- two variables declared, the first is said to be the index
- and the second is said to be the value. The index
- must be of the same type as the indexing type of the associative
- array. It cannot be inout,
- and it is set to be the index of the array element.
-
-
- double[char[]] a; // index type is char[], value type is double
- ...
- foreach (char[] s, double d; a)
- {
- printf("a['%.*s'] = %g\n", s, d);
- }
-
-
- If the aggregate expression is a static or dynamic array, the
- elements are iterated over starting at index 0 and continuing
- to the maximum of the array. If it is an associative array,
- the order of the elements is undefined. If it is a struct or
- class object, it is defined by the special opApply member function.
-
- int opApply(int delegate(inout Type [, ...]) dg);
-
-
- where Type matches the Type used in the foreach
- declaration of Identifier. Multiple ForeachTypes
- correspond with multiple Type's in the delegate type
- passed to opApply.
- There can be multiple opApply functions, one is selected
- by matching the type of dg to the ForeachTypes
- of the ForeachStatement.
- The body of the opApply
- function iterates over the elements it aggregates, passing them
- each to the dg function. If the dg returns 0, then
- opApply goes on to the next element.
- If the dg returns a nonzero value, opApply must cease
- iterating and return that value. Otherwise, after done iterating
- across all the elements, opApply will return 0.
-
- class Foo
- {
- uint array[2];
-
- int opApply(int delegate(inout uint) dg)
- { int result = 0;
-
- for (int i = 0; i < array.length; i++)
- {
- result = dg(array[i]);
- if (result)
- break;
- }
- return result;
- }
- }
-
-
- An example using this might be:
-
-
- void test()
- {
- Foo a = new Foo();
-
- a.array[0] = 73;
- a.array[1] = 82;
-
- foreach (uint u; a)
- {
- printf("%d\n", u);
- }
- }
-
-
- which would print:
-
-
- 73
- 82
-
-
- Aggregates can be string literals, which can be accessed
- as char, wchar, or dchar arrays:
-
-
- void test()
- {
- foreach (char c; "ab")
- {
- printf("'%c'\n", c);
- }
- foreach (wchar w; "xy")
- {
- wprintf("'%c'\n", w);
- }
- }
-
-
- which would print:
-
-
- 'a'
- 'b'
- 'x'
- 'y'
-
-
- inout can be used to update the original elements:
-
-
- void test()
- {
- static uint[2] a = [7, 8];
-
- foreach (inout uint u; a)
- {
- u++;
- }
- foreach (uint u; a)
- {
- printf("%d\n", u);
- }
- }
-
-
- which would print:
-
-
- 8
- 9
-
-
-
-
- The aggregate itself must not be resized, reallocated, free'd,
- reassigned or destructed
- while the foreach is iterating over the elements.
-
-
- int[] a;
- int[] b;
- foreach (int i; a)
- {
- a = null; // error
- a.length += 10; // error
- a = b; // error
- }
- a = null; // ok
-
-
- A BreakStatement in the body of the foreach will exit the
- foreach, a ContinueStatement will immediately start the
- next iteration.
-
-Switch Statement
-
- A switch statement goes to one of a collection of case
- statements depending on the value of the switch
- expression.
-
-
- SwitchStatement:
- switch ( Expression ) BlockStatement
-
- CaseStatement:
- case ExpressionList : Statement
-
- DefaultStatement:
- default: Statement
-
-
- Expression is evaluated. The result type T must be
- of integral type or char[] or wchar[]. The result is
- compared against each of the case expressions. If there is
- a match, the corresponding case statement is transferred to.
-
- switch (i)
- {
- case 1:
- {
- case 2:
- }
- break;
- }
-
-
- Like in C and C++, case statements 'fall through' to subsequent
- case values. A break statement will exit the switch BlockStatement.
- For example:
-
-
- switch (i)
- {
- case 1:
- x = 3;
- case 2:
- x = 4;
- break;
-
- case 3,4,5:
- x = 5;
- break;
- }
-
-
- will set x to 4 if i is 1.
-
- char[] name;
- ...
- switch (name)
- {
- case "fred":
- case "sally":
- ...
- }
-
-
- For applications like command line switch processing, this
- can lead to much more straightforward code, being clearer and
- less error prone. Both ascii and wchar strings are allowed.
- Continue Statement
-
- A continue aborts the current iteration of its enclosing loop
- statement, and starts the next iteration.
-
-
- ContinueStatement:
- continue;
- continue Identifier ;
-
-
- continue executes the next iteration of its innermost enclosing
- while, for, or do loop. The increment clause is executed.
- Break Statement
-
- A break exits the enclosing statement.
-
-
- BreakStatement:
- break;
- break Identifier ;
-
-
- break exits the innermost enclosing while, for, do, or switch
- statement, resuming execution at the statement following it.
- Return Statement
-
- A return exits the current function and supplies its return
- value.
-
-
- ReturnStatement:
- return;
- return Expression ;
-
-
- Expression is required if the function specifies
- a return type that is not void.
- The Expression is implicitly converted to the
- function return type.
- Goto Statement
-
- A goto transfers to the statement labelled with
- Identifier.
-
-
- GotoStatement:
- goto Identifier ;
- goto default ;
- goto case ;
- goto case Expression ;
-
-
- The second form, goto default;, transfers to the
- innermost DefaultStatement of an enclosing SwitchStatement.
- With Statement
-
- The with statement is a way to simplify repeated references
- to the same object.
-
-
- WithStatement:
- with ( Expression ) BlockStatement
- with ( Symbol ) BlockStatement
- with ( TemplateInstance ) BlockStatement
-
-
- where Expression evaluates to a class instance or struct
- reference.
- Within the with body the referenced object is searched first for
- identifier symbols. The WithStatement
-
-
- with (expression)
- {
- ...
- ident;
- }
-
-
- is semantically equivalent to:
-
-
- {
- Object tmp;
- tmp = expression;
- ...
- tmp.ident;
- }
-
-
- Note that expression only gets evaluated once.
- The with statement does not change what this or
- super refer to.
-
- struct Foo
- {
- typedef int Y;
- }
- ...
- Y y; // error, Y undefined
- with (Foo)
- {
- Y y; // same as Foo.Y y;
- }
-
-
-Synchronize Statement
-
- The synchronize statement wraps a statement with
- critical section to synchronize access among multiple threads.
-
-
- SynchronizeStatement:
- synchronized Statement
- synchronized ( Expression ) Statement
-
-
- synchronized allows only one thread at a time to execute Statement.
-
- synchronized { ... }
-
-
- This implements a standard critical section.
-
-Try Statement
-
- Exception handling is done with the try-catch-finally statement.
-
-
- TryStatement:
- try BlockStatement Catches
- try BlockStatement Catches FinallyStatement
- try BlockStatement FinallyStatement
-
- Catches:
- LastCatch
- Catch
- Catch Catches
-
- LastCatch:
- catch BlockStatement
-
- Catch:
- catch ( CatchParameter ) BlockStatement
-
- FinallyStatement:
- finally BlockStatement
-
-
- Parameter declares a variable v of type T, where T is Object
- or derived from Object. v is initialized by the throw expression if
- T is of the same type or a base class of the throw expression.
- The catch clause will be executed if the exception object is of
- type T or derived from T.
-
- int main()
- {
- try
- {
- try
- {
- throw new Exception("first");
- }
- finally
- {
- printf("finally\n");
- throw new Exception("second");
- }
- }
- catch(Exception e)
- {
- printf("catch %.*s\n", e.msg);
- }
- printf("done\n");
- }
-
- prints:
-
- finally
- catch second
- done
-
- A FinallyStatement may not exit with a goto, break,
- continue, or return; nor may it be entered with a goto.
- Throw Statement
-
- Throw an exception.
-
-
- ThrowStatement:
- throw Expression ;
-
-
- Expression is evaluated and must be an Object reference.
- The Object reference is thrown as an exception.
-
-Volatile Statement
-
- No code motion occurs across volatile statement boundaries.
-
-
- VolatileStatement:
- volatile Statement
-
-
- Statement is evaluated.
- Memory writes occurring before the Statement are
- performed before any reads within or after the Statement.
- Memory reads occurring after the Statement occur after
- any writes before or within Statement are completed.
- Asm Statement
-
- Inline assembler is supported with the asm statement:
-
-
- AsmStatement:
- asm { }
- asm { AsmInstructionList }
-
- AsmInstructionList:
- AsmInstruction ;
- AsmInstruction ; AsmInstructionList
-
-
- An asm statement enables the direct use of assembly language
- instructions. This makes it easy to obtain direct access to special
- CPU features without resorting to an external assembler. The
- D compiler will take care of the function calling conventions,
- stack setup, etc.
-
-
-
- These rules exist to ensure that D source code can be tokenized
- independently of syntactic or semantic analysis.
-
- int x = 3;
- asm
- {
- mov EAX,x; // load x and put it in register EAX
- }
-
-
- Inline assembler can be used to access hardware directly:
-
-
- int gethardware()
- {
- asm
- {
- mov EAX, dword ptr 0x1234;
- }
- }
-
-
- For some D implementations, such as a translator from D to C, an
- inline assembler makes no sense, and need not be implemented.
- The version statement can be used to account for this:
-
-
- version (InlineAsm)
- {
- asm
- {
- ...
- }
- }
- else
- {
- ... some workaround ...
- }
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Last update Thu May 19 2005
+
+
+
+Statements
+
+C and C++ programmers will find the D statements very familiar, with a few
+interesting additions.
+
+Labelled Statements
+
+ Statements can be labelled. A label is an identifier that
+ precedes a statement.
+
+
+
+
+ LabelledStatement:
+ Identifier ':' Statement
+
Block Statement
+
+ A block statement is a sequence of statements enclosed
+ by { }. The statements are executed in lexical order.
+
+
+
+
+ BlockStatement:
+ { }
+ { StatementList }
+
+ StatementList:
+ Statement
+ Statement StatementList
+
+
+
+ void func1(int x)
+ { int x; // illegal, x is multiply defined in function scope
+ }
+
+ void func2()
+ {
+ int x;
+
+ { int x; // illegal, x is multiply defined in function scope
+ }
+ }
+
+ void func3()
+ {
+ { int x;
+ }
+ { int x; // illegal, x is multiply defined in function scope
+ }
+ }
+
+ void func4()
+ {
+ { int x;
+ }
+ { x++; // illegal, x is undefined
+ }
+ }
+
Expression Statement
+
+ The expression is evaluated.
+
+
+
+
+ ExpressionStatement:
+ Expression ;
+
Declaration Statement
+
+ Declaration statements declare and initialize variables.
+
+
+
+
+ DeclarationStatement:
+ Type IdentifierList ;
+
+ IdentifierList:
+ Variable
+ Variable , IdentifierList
+
+ Variable:
+ Identifier
+ Identifier = AssignmentExpression
+
If Statement
+
+ If statements provide simple conditional execution of statements.
+
+
+
+
+ IfStatement:
+ if ( Expression ) Statement
+ if ( Expression ) Statement else Statement
+
While Statement
+
+ While statements implement simple loops.
+
+
+
+
+ WhileStatement:
+ while ( Expression ) Statement
+
Do-While Statement
+
+ Do-While statements implement simple loops.
+
+
+
+
+ DoStatement:
+ do Statement while ( Expression )
+
For Statement
+
+ For statements implement loops with initialization,
+ test, and increment clauses.
+
+
+
+
+ ForStatement:
+ for (Initialize; Test; Increment) Statement
+
+ Initialize:
+ empty
+ Expression
+ Declaration
+
+ Test:
+ empty
+ Expression
+
+ Increment:
+ empty
+ Expression
+
+
+
+ for (int i = 0; i < 10; i++)
+ foo(i);
+
+
+
+ { int i;
+ for (i = 0; i < 10; i++)
+ foo(i);
+ }
+
+
+
+ for (int i = 0; i < 10; i++)
+ ; // illegal
+
+
+
+ for (int i = 0; i < 10; i++)
+ {
+ }
+
Foreach Statement
+
+ A foreach statement loops over the contents of an aggregate.
+
+
+
+
+ ForeachStatement:
+ foreach (ForeachTypeList; Expression) Statement
+
+ ForeachTypeList:
+ ForeachType
+ ForeachType , ForeachTypeList
+
+ ForeachType:
+ inout Type Identifier
+ Type Identifier
+
+
+
+ char[] a;
+ ...
+ foreach (int i, char c; a)
+ {
+ printf("a[%d] = '%c'\n", i, c);
+ }
+
+
+
+ char[] a = "\xE2\x89\xA0"; // \u2260 encoded as 3 UTF-8 bytes
+
+ foreach (dchar c; a)
+ {
+ printf("a[] = %x\n", c); // prints 'a[] = 2260'
+ }
+
+ dchar[] b = "\u2260";
+
+ foreach (char c; b)
+ {
+ printf("%x, ", c); // prints 'e2, 89, a0'
+ }
+
+
+
+ double[char[]] a; // index type is char[], value type is double
+ ...
+ foreach (char[] s, double d; a)
+ {
+ printf("a['%.*s'] = %g\n", s, d);
+ }
+
+
+
+ int opApply(int delegate(inout Type [, ...]) dg);
+
+
+
+ class Foo
+ {
+ uint array[2];
+
+ int opApply(int delegate(inout uint) dg)
+ { int result = 0;
+
+ for (int i = 0; i < array.length; i++)
+ {
+ result = dg(array[i]);
+ if (result)
+ break;
+ }
+ return result;
+ }
+ }
+
+
+
+ void test()
+ {
+ Foo a = new Foo();
+
+ a.array[0] = 73;
+ a.array[1] = 82;
+
+ foreach (uint u; a)
+ {
+ printf("%d\n", u);
+ }
+ }
+
+ 73
+ 82
+
+
+ Aggregates can be string literals, which can be accessed
+ as char, wchar, or dchar arrays:
+
+
+
+
+ void test()
+ {
+ foreach (char c; "ab")
+ {
+ printf("'%c'\n", c);
+ }
+ foreach (wchar w; "xy")
+ {
+ wprintf("'%c'\n", w);
+ }
+ }
+
+ 'a'
+ 'b'
+ 'x'
+ 'y'
+
+
+ inout can be used to update the original elements:
+
+
+
+
+ void test()
+ {
+ static uint[2] a = [7, 8];
+
+ foreach (inout uint u; a)
+ {
+ u++;
+ }
+ foreach (uint u; a)
+ {
+ printf("%d\n", u);
+ }
+ }
+
+ 8
+ 9
+
+
+
+
+ The aggregate itself must not be resized, reallocated, free'd,
+ reassigned or destructed
+ while the foreach is iterating over the elements.
+
+
+
+
+ int[] a;
+ int[] b;
+ foreach (int i; a)
+ {
+ a = null; // error
+ a.length += 10; // error
+ a = b; // error
+ }
+ a = null; // ok
+
Switch Statement
+
+ A switch statement goes to one of a collection of case
+ statements depending on the value of the switch
+ expression.
+
+
+
+
+ SwitchStatement:
+ switch ( Expression ) BlockStatement
+
+ CaseStatement:
+ case ExpressionList : Statement
+
+ DefaultStatement:
+ default: Statement
+
+
+
+ switch (i)
+ {
+ case 1:
+ {
+ case 2:
+ }
+ break;
+ }
+
+
+
+ switch (i)
+ {
+ case 1:
+ x = 3;
+ case 2:
+ x = 4;
+ break;
+
+ case 3,4,5:
+ x = 5;
+ break;
+ }
+
+
+
+ char[] name;
+ ...
+ switch (name)
+ {
+ case "fred":
+ case "sally":
+ ...
+ }
+
Continue Statement
+
+ A continue aborts the current iteration of its enclosing loop
+ statement, and starts the next iteration.
+
+
+
+
+ ContinueStatement:
+ continue;
+ continue Identifier ;
+
Break Statement
+
+ A break exits the enclosing statement.
+
+
+
+
+ BreakStatement:
+ break;
+ break Identifier ;
+
Return Statement
+
+ A return exits the current function and supplies its return
+ value.
+
+
+
+
+ ReturnStatement:
+ return;
+ return Expression ;
+
Goto Statement
+
+ A goto transfers to the statement labelled with
+ Identifier.
+
+
+
+
+ GotoStatement:
+ goto Identifier ;
+ goto default ;
+ goto case ;
+ goto case Expression ;
+
With Statement
+
+ The with statement is a way to simplify repeated references
+ to the same object.
+
+
+
+
+ WithStatement:
+ with ( Expression ) BlockStatement
+ with ( Symbol ) BlockStatement
+ with ( TemplateInstance ) BlockStatement
+
+
+
+ with (expression)
+ {
+ ...
+ ident;
+ }
+
+
+
+ {
+ Object tmp;
+ tmp = expression;
+ ...
+ tmp.ident;
+ }
+
+
+
+ struct Foo
+ {
+ typedef int Y;
+ }
+ ...
+ Y y; // error, Y undefined
+ with (Foo)
+ {
+ Y y; // same as Foo.Y y;
+ }
+
Synchronize Statement
+
+ The synchronize statement wraps a statement with
+ critical section to synchronize access among multiple threads.
+
+
+
+
+ SynchronizeStatement:
+ synchronized Statement
+ synchronized ( Expression ) Statement
+
+
+
+ synchronized { ... }
+
Try Statement
+
+ Exception handling is done with the try-catch-finally statement.
+
+
+
+
+ TryStatement:
+ try BlockStatement Catches
+ try BlockStatement Catches FinallyStatement
+ try BlockStatement FinallyStatement
+
+ Catches:
+ LastCatch
+ Catch
+ Catch Catches
+
+ LastCatch:
+ catch BlockStatement
+
+ Catch:
+ catch ( CatchParameter ) BlockStatement
+
+ FinallyStatement:
+ finally BlockStatement
+
+
+
+ int main()
+ {
+ try
+ {
+ try
+ {
+ throw new Exception("first");
+ }
+ finally
+ {
+ printf("finally\n");
+ throw new Exception("second");
+ }
+ }
+ catch(Exception e)
+ {
+ printf("catch %.*s\n", e.msg);
+ }
+ printf("done\n");
+ }
+
+ finally
+ catch second
+ done
+
+ A FinallyStatement may not exit with a goto, break,
+ continue, or return; nor may it be entered with a goto.
+ Throw Statement
+
+ Throw an exception.
+
+
+
+
+ ThrowStatement:
+ throw Expression ;
+
Volatile Statement
+
+ No code motion occurs across volatile statement boundaries.
+
+
+
+
+ VolatileStatement:
+ volatile Statement
+
Asm Statement
+
+ Inline assembler is supported with the asm statement:
+
+
+
+
+ AsmStatement:
+ asm { }
+ asm { AsmInstructionList }
+
+ AsmInstructionList:
+ AsmInstruction ;
+ AsmInstruction ; AsmInstructionList
+
+
+
+ These rules exist to ensure that D source code can be tokenized
+ independently of syntactic or semantic analysis.
+
+
+
+ int x = 3;
+ asm
+ {
+ mov EAX,x; // load x and put it in register EAX
+ }
+
+
+
+ int gethardware()
+ {
+ asm
+ {
+ mov EAX, dword ptr 0x1234;
+ }
+ }
+
+
+
+ version (InlineAsm)
+ {
+ asm
+ {
+ ...
+ }
+ }
+ else
+ {
+ ... some workaround ...
+ }
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+
+
+std.boxer
+
+ This module is a set of types and functions for converting any object
+ (value or heap) into a generic box type, allowing the user to pass that
+ object around without knowing what's in the box, and then allowing him
+ to recover the value afterwards.
+
+
+
+ // Convert the integer 45 into a box.
+ Box b = box(45);
+
+ // Recover the integer and cast it to real.
+ real r = unbox!(real)(b);
+
+
+
+ // Convert arguments into an array of boxes.
+ Box[] a = boxArray(1, 45.4, "foobar");
+
+ // Convert an array of boxes back into arguments.
+ TypeInfo[] arg_types;
+ void* arg_data;
+
+ boxArrayToArguments(a, arg_types, arg_data);
+
+ // Convert the arguments back into boxes using a
+ // different form of the function.
+ a = boxArray(arg_types, arg_data);
+
+
+
+
+
+
diff -uNr dmd-0.123/dmd/html/d/struct.html dmd-0.124/dmd/html/d/struct.html
--- dmd-0.123/dmd/html/d/struct.html 2005-04-15 14:13:42.000000000 +0200
+++ dmd-0.124/dmd/html/d/struct.html 2005-05-19 11:44:48.000000000 +0200
@@ -1,137 +1,160 @@
-
-
-
-
-
-
+
+
+
+
+
Box[] boxArray(...)
+
+
+
+
+ Box b = box(4.5);
+ bit u = unboxable!(real)(b); // This is true.
+ real r = unbox!(real)(b);
+
+
+
+
Last update Mar 14, 2005
-
-
-Structs & Unions
-
-
- AggregateDeclaration:
- Tag { DeclDefs }
- Tag Identifier StructBody
- Tag Identifier ;
-
- Tag:
- struct
- union
-
- StructBody:
- { }
- { StructBodyDeclarations }
-
- StructBodyDeclarations:
- StructBodyDeclaration
- StructBodyDeclaration StructBodyDeclarations
-
- StructBodyDeclaration:
- Declaration
- Invariant
- UnitTest
- StructAllocator
- StructDeallocator
-
-
-They work like they do in C, with the following exceptions:
-
-
-
-
-Structs and unions are meant as simple aggregations of data, or as a way to paint a
-data structure over hardware or an external type. External types can be defined by
-the operating system API, or by a file format. Object oriented features are
-provided with the class data type.
-
-
-
- struct ABC x;
-
- are not allowed, replace with:
-
- ABC x;
-
- Static Initialization of Structs
-
- Static struct members are by default initialized to whatever the
- default initializer for the member is, and if none supplied, to
- the default initializer for the member's type.
- If a static initializer is supplied, the
- members are initialized by the member name,
- colon, expression syntax. The members may be initialized in any order.
- Members not specified in the initializer list are default initialized.
-
-
- struct X { int a; int b; int c; int d = 7;}
- static X x = { a:1, b:2}; // c is set to 0, d to 7
- static X z = { c:4, b:5, a:2 , d:5}; // z.a = 2, z.b = 5, z.c = 4, z.d = 5
-
-
- C-style initialization, based on the order of the members in the
- struct declaration, is also supported:
-
-
- static X q = { 1, 2 }; // q.a = 1, q.b = 2, q.c = 0, q.d = 7
-
-
-
-Static Initialization of Unions
-
- Unions are initialized explicitly.
-
-
- union U { int a; double b; }
- static U u = { b : 5.0 }; // u.b = 5.0
-
-
- Other members of the union that overlay the initializer,
- but occupy more storage, have
- the extra storage initialized to zero.
-
-Struct Properties
-
-
- .sizeof Size in bytes of struct
- .alignof Size boundary struct needs to be aligned on
-
-
-Struct Field Properties
-
-
- .offsetof Offset in bytes of field from beginning
- of struct
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Last update Thu May 19 2005
+
+
+Structs & Unions
+
+
+ AggregateDeclaration:
+ Tag { DeclDefs }
+ Tag Identifier StructBody
+ Tag Identifier ;
+
+ Tag:
+ struct
+ union
+
+ StructBody:
+ { }
+ { StructBodyDeclarations }
+
+ StructBodyDeclarations:
+ StructBodyDeclaration
+ StructBodyDeclaration StructBodyDeclarations
+
+ StructBodyDeclaration:
+ Declaration
+ Invariant
+ UnitTest
+ StructAllocator
+ StructDeallocator
+
+
+They work like they do in C, with the following exceptions:
+
+
+
+
+Structs and unions are meant as simple aggregations of data, or as a way to paint a
+data structure over hardware or an external type. External types can be defined by
+the operating system API, or by a file format. Object oriented features are
+provided with the class data type.
+
+
+
+ struct ABC x;
+
+ are not allowed, replace with:
+
+ ABC x;
+
+ Static Initialization of Structs
+
+ Static struct members are by default initialized to whatever the
+ default initializer for the member is, and if none supplied, to
+ the default initializer for the member's type.
+ If a static initializer is supplied, the
+ members are initialized by the member name,
+ colon, expression syntax. The members may be initialized in any order.
+ Members not specified in the initializer list are default initialized.
+
+
+ struct X { int a; int b; int c; int d = 7;}
+ static X x = { a:1, b:2}; // c is set to 0, d to 7
+ static X z = { c:4, b:5, a:2 , d:5}; // z.a = 2, z.b = 5, z.c = 4, z.d = 5
+
+
+ C-style initialization, based on the order of the members in the
+ struct declaration, is also supported:
+
+
+ static X q = { 1, 2 }; // q.a = 1, q.b = 2, q.c = 0, q.d = 7
+
+
+
+Static Initialization of Unions
+
+ Unions are initialized explicitly.
+
+
+ union U { int a; double b; }
+ static U u = { b : 5.0 }; // u.b = 5.0
+
+
+ Other members of the union that overlay the initializer,
+ but occupy more storage, have
+ the extra storage initialized to zero.
+
+Struct Properties
+
+
+ .sizeof Size in bytes of struct
+ .alignof Size boundary struct needs to be aligned on
+
+
+Struct Field Properties
+
+
+ .offsetof Offset in bytes of field from beginning
+ of struct
+
+
+Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last modified Apr 4, 2005
-
-
-Templates
-
- Templates are D's approach to generic programming.
- Templates are defined with a TemplateDeclaration:
-
-
- TemplateDeclaration:
- template TemplateIdentifier ( TemplateParameterList )
- { DeclDefs }
-
- TemplateIdentifier:
- Identifier
-
- TemplateParameterList
- TemplateParameter
- TemplateParameter , TemplateParameterList
-
- TemplateParameter:
- TypeParameter
- ValueParameter
- AliasParameter
-
- TemplateTypeParameter:
- Identifier
- Identifier TemplateTypeParameterSpecialization
- Identifier TemplateTypeParameterDefault
- Identifier TemplateTypeParameterSpecialization TemplateTypeParameterDefault
-
- TemplateTypeParameterSpecialization:
- : Type
-
- TemplateTypeParameterDefault:
- = Type
-
- TemplateValueParameter:
- Declaration
- Declaration TemplateValueParameterSpecialization
- Declaration TemplateValueParameterDefault
- Declaration TemplateValueParameterSpecialization TemplateValueParameterDefault
-
- TemplateValueParameterSpecialization:
- : ConditionalExpression
-
- TemplateValueParameterDefault:
- = ConditionalExpression
-
- TemplateAliasParameter:
- alias Identifier
- alias Identifier TemplateAliasParameterSpecialization
- alias Identifier TemplateAliasParameterDefault
- alias Identifier TemplateAliasParameterSpecialization TemplateAliasParameterDefault
-
- TemplateValueParameterSpecialization:
- : Type
-
- TemplateAliasParameterDefault:
- = Type
-
-
- The body of the TemplateDeclaration must be syntactically correct
- even if never instantiated. Semantic analysis is not done until
- instantiated. A template forms its own scope, and the template
- body can contain classes, structs, types, enums, variables,
- functions, and other templates.
- Template Instantiation
-
- Templates are instantiated with:
-
-
- TemplateInstance:
- TemplateIdentifer !( TemplateArgumentList )
-
- TemplateArgumentList:
- TemplateArgument
- TemplateArgument , TemplateArgumentList
-
- TemplateArgument:
- Type
- AssignExpression
- Symbol
-
-
- Once instantiated, the declarations inside the template, called
- the template members, are in the scope
- of the TemplateInstance:
-
-
- template TFoo(T) { alias T* t; }
- ...
- TFoo!(int).t x; // declare x to be of type int*
-
-
- A template instantiation can be aliased:
-
-
- template TFoo(T) { alias T* t; }
- alias TFoo!(int) abc;
- abc.t x; // declare x to be of type int*
-
-
- Multiple instantiations of a TemplateDeclaration with the same
- TemplateParameterList all will refer to the same instantiation.
- For example:
-
- template TFoo(T) { T f; }
- alias TFoo(int) a;
- alias TFoo(int) b;
- ...
- a.f = 3;
- assert(b.f == 3); // a and b refer to the same instance of TFoo
-
-
- This is true even if the TemplateInstances are done in
- different modules.
-
- template TCopy(T)
- {
- void copy(out T to, T from)
- {
- to = from;
- }
- }
-
-
- To use the template, it must first be instantiated with a specific
- type:
-
-
- int i;
- TCopy!(int).copy(i, 3);
-
-
-
-Instantiation Scope
-
- TemplateInstantances are always performed in the scope of where
- the TemplateDeclaration is declared, with the addition of the
- template parameters being declared as aliases for their deduced types.
-
- -------- module a ---------
- template TFoo(T) { void bar() { func(); } }
-
- -------- module b ---------
- import a;
-
- void func() { }
- alias TFoo!(int) f; // error: func not defined in module a
-
-
- and:
-
-
- -------- module a ---------
- template TFoo(T) { void bar() { func(1); } }
- void func(double d) { }
-
- -------- module b ---------
- import a;
-
- void func(int i) { }
- alias TFoo!(int) f;
- ...
- f.bar(); // will call a.func(double)
-
-
- TemplateParameter specializations and default
- values are evaluated in the scope of the TemplateDeclaration.
-
-Argument Deduction
-
- The types of template parameters are deduced for a particular
- template instantiation by comparing the template argument with
- the corresponding template parameter.
-
-
-
- For example:
-
- template TFoo(T) { }
- alias TFoo!(int) Foo1; // (1) T is deduced to be int
- alias TFoo!(char*) Foo2; // (1) T is deduced to be char*
-
- template TFoo(T : T*) { }
- alias TFoo!(char*) Foo3; // (2) T is deduced to be char
-
- template TBar(D, U : D[]) { }
- alias TBar!(int, int[]) Bar1; // (2) D is deduced to be int, U is int[]
- alias TBar!(char, int[]) Bar2; // (4) error, D is both char and int
-
- template TBar(D : E*, E) { }
- alias TBar!(int*, int) Bar3; // (1) E is int
- // (3) D is int*
-
-
- When considering matches, a class is
- considered to be a match for any super classes or interfaces:
-
-
- class A { }
- class B : A { }
-
- template TFoo(T : A) { }
- alias TFoo!(B) Foo4; // (3) T is B
-
- template TBar(T : U*, U : A) { }
- alias TBar!(B*, B) Foo5; // (2) T is B*
- // (3) U is B
-
-
-Value Parameters
-
- This example of template foo has a value parameter that
- is specialized for 10:
-
-
- template foo(U : int, int T : 10)
- {
- U x = T;
- }
-
- void main()
- {
- assert(foo!(int, 10).x == 10);
- }
-
-
-
-Specialization
-
- Templates may be specialized for particular types of arguments
- by following the template parameter identifier with a : and the
- specialized type.
- For example:
-
-
- template TFoo(T) { ... } // #1
- template TFoo(T : T[]) { ... } // #2
- template TFoo(T : char) { ... } // #3
- template TFoo(T,U,V) { ... } // #4
-
- alias TFoo!(int) foo1; // instantiates #1
- alias TFoo!(double[]) foo2; // instantiates #2 with T being double
- alias TFoo!(char) foo3; // instantiates #3
- alias TFoo!(char, int) fooe; // error, number of arguments mismatch
- alias TFoo!(char, int, int) foo4; // instantiates #4
-
-
- The template picked to instantiate is the one that is most specialized
- that fits the types of the TemplateArgumentList.
- Determine which is more specialized is done the same way as the
- C++ partial ordering rules.
- If the result is ambiguous, it is an error.
-
-Alias Parameters
-
- Alias parameters enable templates to be parameterized with
- any type of D symbol, including global names, type names,
- module names, template names, and template instance names.
- Local names may not be used as alias parameters.
- It is a superset of the uses of template template parameters in C++.
-
-
-
-
-
- int x;
-
- template Foo(alias X)
- {
- static int* p = &X;
- }
-
- void test()
- {
- alias Foo!(x) bar;
- *bar.p = 3; // set x to 3
- int y;
- alias Foo!(y) abc; // error, y is local name
- }
-
-
- class Foo
- {
- static int p;
- }
-
- template Bar(alias T)
- {
- alias T.p q;
- }
-
- void test()
- {
- alias Bar!(Foo) bar;
- bar.q = 3; // sets Foo.p to 3
- }
-
-
- import std.string;
-
- template Foo(alias X)
- {
- alias X.toString y;
- }
-
- void test()
- {
- alias Foo!(std.string) bar;
- bar.y(3); // calls std.string.toString(3)
- }
-
-
- int x;
-
- template Foo(alias X)
- {
- static int* p = &X;
- }
-
- template Bar(alias T)
- {
- alias T!(x) abc;
- }
-
- void test()
- {
- alias Bar!(Foo) bar;
- *bar.abc.p = 3; // sets x to 3
- }
-
-
- int x;
-
- template Foo(alias X)
- {
- static int* p = &X;
- }
-
- template Bar(alias T)
- {
- alias T.p q;
- }
-
- void test()
- {
- alias Foo!(x) foo;
- alias Bar!(foo) bar;
- *bar.q = 3; // sets x to 3
- }
-
- Template Parameter Default Values
-
- Trailing template parameters can be given default values:
-
-
- template Foo(T, U = int) { ... }
- Foo!(uint,long); // instantiate Foo with T as uint, and U as long
- Foo!(uint); // instantiate Foo with T as uint, and U as int
-
- template Foo(T, U = T*) { ... }
- Foo!(uint); // instantiate Foo with T as uint, and U as uint*
-
-
-Implicit Template Properties
-
- If a template has exactly one member in it, and the name of that
- member is the same as the template name, that member is assumed
- to be referred to in a template instantiation:
-
-
- template Foo(T)
- {
- T Foo; // declare variable Foo of type T
- }
-
- void test()
- {
- Foo!(int) = 6; // instead of Foo!(int).Foo
- }
-
-
-Class Templates
-
-
- ClassTemplateDeclaration:
- class Identifier ( TemplateParameterList ) [SuperClass {, InterfaceClass }] ClassBody
-
-
- If a template declares exactly one member, and that member is a class
- with the same name as the template:
-
-
- template Bar(T)
- {
- class Bar
- {
- T member;
- }
- }
-
-
- then the semantic equivalent, called a ClassTemplateDeclaration
- can be written as:
-
-
- class Bar(T)
- {
- T member;
- }
-
-
-Recursive Templates
-
- Template features can be combined to produce some interesting
- effects, such as compile time evaluation of non-trivial functions.
- For example, a factorial template can be written:
-
-
- template factorial(int n : 1)
- {
- enum { factorial = 1 }
- }
-
- template factorial(int n)
- {
- // Note . used to find global template rather than enum
- enum { factorial = n* .factorial!(n-1) }
- }
-
- void test()
- {
- printf("%d\n", factorial!(4)); // prints 24
- }
-
-
-Limitations
-
- Templates cannot be used to add non-static members or functions
- to classes.
- For example:
-
- class Foo
- {
- template TBar(T)
- {
- T xx; // Error
- int func(T) { ... } // Error
-
- static T yy; // Ok
- static int func(T t, int y) { ... } // Ok
- }
- }
-
-
- Templates cannot be declared inside functions.
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+
+Templates
+
+ Templates are D's approach to generic programming.
+ Templates are defined with a TemplateDeclaration:
+
+
+ TemplateDeclaration:
+ template TemplateIdentifier ( TemplateParameterList )
+ { DeclDefs }
+
+ TemplateIdentifier:
+ Identifier
+
+ TemplateParameterList
+ TemplateParameter
+ TemplateParameter , TemplateParameterList
+
+ TemplateParameter:
+ TypeParameter
+ ValueParameter
+ AliasParameter
+
+ TemplateTypeParameter:
+ Identifier
+ Identifier TemplateTypeParameterSpecialization
+ Identifier TemplateTypeParameterDefault
+ Identifier TemplateTypeParameterSpecialization TemplateTypeParameterDefault
+
+ TemplateTypeParameterSpecialization:
+ : Type
+
+ TemplateTypeParameterDefault:
+ = Type
+
+ TemplateValueParameter:
+ Declaration
+ Declaration TemplateValueParameterSpecialization
+ Declaration TemplateValueParameterDefault
+ Declaration TemplateValueParameterSpecialization TemplateValueParameterDefault
+
+ TemplateValueParameterSpecialization:
+ : ConditionalExpression
+
+ TemplateValueParameterDefault:
+ = ConditionalExpression
+
+ TemplateAliasParameter:
+ alias Identifier
+ alias Identifier TemplateAliasParameterSpecialization
+ alias Identifier TemplateAliasParameterDefault
+ alias Identifier TemplateAliasParameterSpecialization TemplateAliasParameterDefault
+
+ TemplateValueParameterSpecialization:
+ : Type
+
+ TemplateAliasParameterDefault:
+ = Type
+
+
+ The body of the TemplateDeclaration must be syntactically correct
+ even if never instantiated. Semantic analysis is not done until
+ instantiated. A template forms its own scope, and the template
+ body can contain classes, structs, types, enums, variables,
+ functions, and other templates.
+ Template Instantiation
+
+ Templates are instantiated with:
+
+
+ TemplateInstance:
+ TemplateIdentifer !( TemplateArgumentList )
+
+ TemplateArgumentList:
+ TemplateArgument
+ TemplateArgument , TemplateArgumentList
+
+ TemplateArgument:
+ Type
+ AssignExpression
+ Symbol
+
+
+ Once instantiated, the declarations inside the template, called
+ the template members, are in the scope
+ of the TemplateInstance:
+
+
+
+
+ template TFoo(T) { alias T* t; }
+ ...
+ TFoo!(int).t x; // declare x to be of type int*
+
+
+
+ template TFoo(T) { alias T* t; }
+ alias TFoo!(int) abc;
+ abc.t x; // declare x to be of type int*
+
+
+
+ template TFoo(T) { T f; }
+ alias TFoo(int) a;
+ alias TFoo(int) b;
+ ...
+ a.f = 3;
+ assert(b.f == 3); // a and b refer to the same instance of TFoo
+
+
+
+ template TCopy(T)
+ {
+ void copy(out T to, T from)
+ {
+ to = from;
+ }
+ }
+
+
+
+ int i;
+ TCopy!(int).copy(i, 3);
+
Instantiation Scope
+
+ TemplateInstantances are always performed in the scope of where
+ the TemplateDeclaration is declared, with the addition of the
+ template parameters being declared as aliases for their deduced types.
+
+
+
+ -------- module a ---------
+ template TFoo(T) { void bar() { func(); } }
+
+ -------- module b ---------
+ import a;
+
+ void func() { }
+ alias TFoo!(int) f; // error: func not defined in module a
+
+
+
+ -------- module a ---------
+ template TFoo(T) { void bar() { func(1); } }
+ void func(double d) { }
+
+ -------- module b ---------
+ import a;
+
+ void func(int i) { }
+ alias TFoo!(int) f;
+ ...
+ f.bar(); // will call a.func(double)
+
Argument Deduction
+
+ The types of template parameters are deduced for a particular
+ template instantiation by comparing the template argument with
+ the corresponding template parameter.
+
+
+
+ For example:
+
+
+
+ template TFoo(T) { }
+ alias TFoo!(int) Foo1; // (1) T is deduced to be int
+ alias TFoo!(char*) Foo2; // (1) T is deduced to be char*
+
+ template TFoo(T : T*) { }
+ alias TFoo!(char*) Foo3; // (2) T is deduced to be char
+
+ template TBar(D, U : D[]) { }
+ alias TBar!(int, int[]) Bar1; // (2) D is deduced to be int, U is int[]
+ alias TBar!(char, int[]) Bar2; // (4) error, D is both char and int
+
+ template TBar(D : E*, E) { }
+ alias TBar!(int*, int) Bar3; // (1) E is int
+ // (3) D is int*
+
+
+
+ class A { }
+ class B : A { }
+
+ template TFoo(T : A) { }
+ alias TFoo!(B) Foo4; // (3) T is B
+
+ template TBar(T : U*, U : A) { }
+ alias TBar!(B*, B) Foo5; // (2) T is B*
+ // (3) U is B
+
Value Parameters
+
+ This example of template foo has a value parameter that
+ is specialized for 10:
+
+
+
+
+ template foo(U : int, int T : 10)
+ {
+ U x = T;
+ }
+
+ void main()
+ {
+ assert(foo!(int, 10).x == 10);
+ }
+
Specialization
+
+ Templates may be specialized for particular types of arguments
+ by following the template parameter identifier with a : and the
+ specialized type.
+ For example:
+
+
+
+
+ template TFoo(T) { ... } // #1
+ template TFoo(T : T[]) { ... } // #2
+ template TFoo(T : char) { ... } // #3
+ template TFoo(T,U,V) { ... } // #4
+
+ alias TFoo!(int) foo1; // instantiates #1
+ alias TFoo!(double[]) foo2; // instantiates #2 with T being double
+ alias TFoo!(char) foo3; // instantiates #3
+ alias TFoo!(char, int) fooe; // error, number of arguments mismatch
+ alias TFoo!(char, int, int) foo4; // instantiates #4
+
Alias Parameters
+
+ Alias parameters enable templates to be parameterized with
+ any type of D symbol, including global names, type names,
+ module names, template names, and template instance names.
+ Local names may not be used as alias parameters.
+ It is a superset of the uses of template template parameters in C++.
+
+
+
+
+
+
+
+ int x;
+
+ template Foo(alias X)
+ {
+ static int* p = &X;
+ }
+
+ void test()
+ {
+ alias Foo!(x) bar;
+ *bar.p = 3; // set x to 3
+ int y;
+ alias Foo!(y) abc; // error, y is local name
+ }
+
+
+ class Foo
+ {
+ static int p;
+ }
+
+ template Bar(alias T)
+ {
+ alias T.p q;
+ }
+
+ void test()
+ {
+ alias Bar!(Foo) bar;
+ bar.q = 3; // sets Foo.p to 3
+ }
+
+
+ import std.string;
+
+ template Foo(alias X)
+ {
+ alias X.toString y;
+ }
+
+ void test()
+ {
+ alias Foo!(std.string) bar;
+ bar.y(3); // calls std.string.toString(3)
+ }
+
+
+ int x;
+
+ template Foo(alias X)
+ {
+ static int* p = &X;
+ }
+
+ template Bar(alias T)
+ {
+ alias T!(x) abc;
+ }
+
+ void test()
+ {
+ alias Bar!(Foo) bar;
+ *bar.abc.p = 3; // sets x to 3
+ }
+
+
+ int x;
+
+ template Foo(alias X)
+ {
+ static int* p = &X;
+ }
+
+ template Bar(alias T)
+ {
+ alias T.p q;
+ }
+
+ void test()
+ {
+ alias Foo!(x) foo;
+ alias Bar!(foo) bar;
+ *bar.q = 3; // sets x to 3
+ }
Template Parameter Default Values
+
+ Trailing template parameters can be given default values:
+
+
+
+
+ template Foo(T, U = int) { ... }
+ Foo!(uint,long); // instantiate Foo with T as uint, and U as long
+ Foo!(uint); // instantiate Foo with T as uint, and U as int
+
+ template Foo(T, U = T*) { ... }
+ Foo!(uint); // instantiate Foo with T as uint, and U as uint*
+
Implicit Template Properties
+
+ If a template has exactly one member in it, and the name of that
+ member is the same as the template name, that member is assumed
+ to be referred to in a template instantiation:
+
+
+
+
+ template Foo(T)
+ {
+ T Foo; // declare variable Foo of type T
+ }
+
+ void test()
+ {
+ Foo!(int) = 6; // instead of Foo!(int).Foo
+ }
+
Class Templates
+
+
+ ClassTemplateDeclaration:
+ class Identifier ( TemplateParameterList ) [SuperClass {, InterfaceClass }] ClassBody
+
+
+ If a template declares exactly one member, and that member is a class
+ with the same name as the template:
+
+
+
+
+ template Bar(T)
+ {
+ class Bar
+ {
+ T member;
+ }
+ }
+
+
+
+ class Bar(T)
+ {
+ T member;
+ }
+
Recursive Templates
+
+ Template features can be combined to produce some interesting
+ effects, such as compile time evaluation of non-trivial functions.
+ For example, a factorial template can be written:
+
+
+
+
+ template factorial(int n : 1)
+ {
+ enum { factorial = 1 }
+ }
+
+ template factorial(int n)
+ {
+ // Note . used to find global template rather than enum
+ enum { factorial = n* .factorial!(n-1) }
+ }
+
+ void test()
+ {
+ printf("%d\n", factorial!(4)); // prints 24
+ }
+
Limitations
+
+ Templates cannot be used to add non-static members or functions
+ to classes.
+ For example:
+
+
+
+ class Foo
+ {
+ template TBar(T)
+ {
+ T xx; // Error
+ int func(T) { ... } // Error
+
+ static T yy; // Ok
+ static int func(T t, int y) { ... } // Ok
+ }
+ }
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
· Mixins
· Contracts
-· Versioning
+· Conditional Compilation
· Handling errors
· Garbage Collection
· Memory Management
diff -uNr dmd-0.123/dmd/html/d/type.html dmd-0.124/dmd/html/d/type.html
--- dmd-0.123/dmd/html/d/type.html 2005-04-15 14:13:42.000000000 +0200
+++ dmd-0.124/dmd/html/d/type.html 2005-05-19 11:44:48.000000000 +0200
@@ -1,275 +1,307 @@
-
-
-
-
-
-
Last update Mar 25, 2005
-
-
-Types
-
-Basic Data Types
-
-
-
-
-
-
-
-
- Keyword
- Description
- Default Initializer (.init)
- void no type -
- bit single bit false
- byte signed 8 bits 0
- ubyte unsigned 8 bits 0
- short signed 16 bits 0
- ushort unsigned 16 bits 0
- int signed 32 bits 0
- uint unsigned 32 bits 0
- long signed 64 bits 0L
- ulong unsigned 64 bits 0L
- cent signed 128 bits (reserved for future use) 0
- ucent unsigned 128 bits (reserved for future use) 0
- float 32 bit floating point float.nan
- double 64 bit floating point double.nan
- real
- largest hardware implemented floating
- point size (Implementation Note: 80 bits for Intel CPU's)
- real.nan
- ifloat
- imaginary float
- float.nan * 1.0i
- idouble
- imaginary double
- double.nan * 1.0i
- ireal
- imaginary real
- real.nan * 1.0i
- cfloat
- a complex number of two float values
- float.nan + float.nan * 1.0i
- cdouble
- complex double
- double.nan + double.nan * 1.0i
- creal
- complex real
- real.nan + real.nan * 1.0i
-
- char unsigned 8 bit UTF-8 0xFF
- wchar unsigned 16 bit UTF-16 0xFFFF
- dchar unsigned 32 bit UTF-32 0x0000FFFF
- Derived Data Types
-
-
-
-
-User Defined Types
-
-
-
-
-Pointer Conversions
-
- Casting pointers to non-pointers and vice versa is allowed in D,
- however, do not do this for any pointers that point to data
- allocated by the garbage collector.
-
-Implicit Conversions
-
-
- D has a lot of types, both built in and derived.
- It would be tedious to require casts for every
- type conversion, so implicit conversions step in
- to handle the obvious ones automatically.
-
- typedef int myint;
- int i;
- myint m;
- i = m; // OK
- m = i; // error
- m = cast(myint)i; // OK
-
-
-Integer Promotions
-
- Integer Promotions are conversions of the following types:
-
-
-
- from
- to
-
- bit
- int
-
- byte
- int
-
- ubyte
- int
-
- short
- int
-
- ushort
- int
-
- char
- int
-
- wchar
- int
-
- dchar
- uint
- Usual Arithmetic Conversions
-
- The usual arithmetic conversions convert operands of binary
- operators to a common type. The operands must already be
- of arithmetic types.
- The following rules are applied
- in order:
-
-
-
-
- Floating point types cannot be implicitly converted to
- integral types.
-
-
- Delegates
-
- There are no pointers-to-members in D, but a more useful
- concept called delegates are supported.
- Delegates are an aggregate of two pieces of data: an
- object reference and a function pointer. The object reference
- forms the this pointer when the function is called.
-
- int function(int) fp; // fp is pointer to a function
- int delegate(int) dg; // dg is a delegate to a function
-
-
- The C style syntax for declaring pointers to functions is
- also supported:
-
-
- int (*fp)(int); // fp is pointer to a function
-
-
- A delegate is initialized analogously to function pointers:
-
-
- int func(int);
- fp = &func; // fp points to func
-
- class OB
- { int member(int);
- }
- OB o;
- dg = &o.member; // dg is a delegate to object o and
- // member function member
-
-
- Delegates cannot be initialized with static member functions
- or non-member functions.
-
- fp(3); // call func(3)
- dg(3); // call o.member(3)
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+
+Types
+
+Basic Data Types
+
+
+
+
+
+
+
+
+ Keyword
+ Description
+ Default Initializer (.init)
+ void no type -
+ bit single bit false
+ byte signed 8 bits 0
+ ubyte unsigned 8 bits 0
+ short signed 16 bits 0
+ ushort unsigned 16 bits 0
+ int signed 32 bits 0
+ uint unsigned 32 bits 0
+ long signed 64 bits 0L
+ ulong unsigned 64 bits 0L
+ cent signed 128 bits (reserved for future use) 0
+ ucent unsigned 128 bits (reserved for future use) 0
+ float 32 bit floating point float.nan
+ double 64 bit floating point double.nan
+ real
+ largest hardware implemented floating
+ point size (Implementation Note: 80 bits for Intel CPU's)
+ real.nan
+ ifloat
+ imaginary float
+ float.nan * 1.0i
+ idouble
+ imaginary double
+ double.nan * 1.0i
+ ireal
+ imaginary real
+ real.nan * 1.0i
+ cfloat
+ a complex number of two float values
+ float.nan + float.nan * 1.0i
+ cdouble
+ complex double
+ double.nan + double.nan * 1.0i
+ creal
+ complex real
+ real.nan + real.nan * 1.0i
+
+ char unsigned 8 bit UTF-8 0xFF
+ wchar unsigned 16 bit UTF-16 0xFFFF
+ dchar unsigned 32 bit UTF-32 0x0000FFFF
+ Derived Data Types
+
+
+
+
+User Defined Types
+
+
+
+
+Pointer Conversions
+
+ Casting pointers to non-pointers and vice versa is allowed in D,
+ however, do not do this for any pointers that point to data
+ allocated by the garbage collector.
+
+Implicit Conversions
+
+
+ D has a lot of types, both built in and derived.
+ It would be tedious to require casts for every
+ type conversion, so implicit conversions step in
+ to handle the obvious ones automatically.
+
+
+
+ typedef int myint;
+ int i;
+ myint m;
+ i = m; // OK
+ m = i; // error
+ m = cast(myint)i; // OK
+
Integer Promotions
+
+ Integer Promotions are conversions of the following types:
+
+
+
+ from
+ to
+
+ bit
+ int
+
+ byte
+ int
+
+ ubyte
+ int
+
+ short
+ int
+
+ ushort
+ int
+
+ char
+ int
+
+ wchar
+ int
+
+ dchar
+ uint
+ Usual Arithmetic Conversions
+
+ The usual arithmetic conversions convert operands of binary
+ operators to a common type. The operands must already be
+ of arithmetic types.
+ The following rules are applied
+ in order:
+
+
+
+
+ Floating point types cannot be implicitly converted to
+ integral types.
+
+
+ Delegates
+
+ There are no pointers-to-members in D, but a more useful
+ concept called delegates are supported.
+ Delegates are an aggregate of two pieces of data: an
+ object reference and a function pointer. The object reference
+ forms the this pointer when the function is called.
+
+
+
+ int function(int) fp; // fp is pointer to a function
+ int delegate(int) dg; // dg is a delegate to a function
+
+
+
+ int (*fp)(int); // fp is pointer to a function
+
+
+
+ int func(int);
+ fp = &func; // fp points to func
+
+ class OB
+ { int member(int);
+ }
+ OB o;
+ dg = &o.member; // dg is a delegate to object o and
+ // member function member
+
+
+
+ fp(3); // call func(3)
+ dg(3); // call o.member(3)
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last modified Nov 3, 2004.
-
-
-Debug, Version, and Static Assert
-
- D supports building multiple versions and various debug
- builds from the same source code using the features:
-
-
- DebugSpecification
- DebugAttribute
- DebugStatement
-
- VersionSpecification
- VersionAttribute
- VersionStatement
-
- StaticAssert
-
-
-Predefined Versions
-
- Several environmental version identifiers and identifier
- name spaces are predefined
- to encourage consistent usage. Version identifiers do not conflict
- with other identifiers in the code, they are in a separate name space.
- Predefined version identifiers are global, i.e. they apply to
- all modules being compiled and imported.
-
-
-
- Others will be added as they make sense and new implementations appear.
-
-
- version(DigitalMars_funky_extension)
- {
- ...
- }
-
-
- It is important to use the right version identifier for the right
- purpose. For example, use the vendor identifier when using a vendor
- specific feature. Use the operating system identifier when using
- an operating system specific feature, etc.
-
-
-
-Specification
-
-
- DebugSpecification
- debug = Identifier ;
- debug = Integer ;
-
- VersionSpecification
- version = Identifier ;
- version = Integer ;
-
-
- Version specifications do not declare any symbols,
- but instead set a version in the same manner that the
- -version does on the command line.
- The version specification is used for conditional
- compilation with
- version attributes
- and
- version statements.
-
- version (ProfessionalEdition)
- {
- version = FeatureA;
- version = FeatureB;
- version = FeatureC;
- }
- version (HomeEdition)
- {
- version = FeatureA;
- }
- ...
- version (FeatureB)
- {
- ... implement Feature B ...
- }
-
-
-Debug Statement
-
- Two versions of programs are commonly built,
- a release build and a debug build.
- The debug build commonly includes extra error checking code,
- test harnesses, pretty-printing code, etc.
- The debug statement conditionally compiles in its
- statement body.
- It is D's way of what in C is done
- with #ifdef DEBUG / #endif pairs.
-
-
- DebugStatement:
- DebugPredicate Statement
- DebugPredicate Statement else Statement
-
- DebugPredicate
- debug Statement
- debug ( Integer )
- debug ( Identifier )
-
-
- Debug statements are compiled in when the -debug switch is
- thrown on the compiler.
-
- int k;
- debug
- { int i;
- int k; // error, k already defined
-
- i = 3;
- }
- x = i; // uses the i declared above
-
-
-Version Statement
-
- It is commonplace to conveniently support multiple versions
- of a module with a single source file.
- While the D way is to isolate all versioning into separate
- modules, that can get burdensome if it's just simple line
- change, or if the entire program would otherwise fit into one module.
-
- VersionStatement:
- VersionPredicate Statement
- VersionPredicate Statement else Statement
-
- VersionPredicate
- version ( Integer )
- version ( Identifier )
-
-
- The version statement conditionally compiles in its
- statement body based on the version specified by the Integer
- of Identifier. Both forms are set by the -version switch
- to the compiler.
-
-
- If Statement is a block statement, it does not
- introduce a new scope. For example:
-
-
- int k;
- version (Demo) // compile in this code block for the demo version
- { int i;
- int k; // error, k already defined
-
- i = 3;
- }
- x = i; // uses the i declared above
-
-
- The version statement works together with the version attribute
- for declarations.
-
- version (X86)
- {
- ... // implement custom inline assembler version
- }
- else
- {
- ... // use default, but slow, version
- }
-
-
- While the debug and version statements superficially behave the same,
- they are intended for very different purposes. Debug statements
- are for adding debug code that is removed for the release version.
- Version statements are to aid in portability and multiple release
- versions.
-
-Debug Attribute
-
-
- DebugAttribute:
- debug
- debug ( Integer )
- debug ( Identifier )
-
-
-
- Two versions of programs are commonly built, a release build and a
- debug build. The debug build includes extra error checking
- code, test harnesses, pretty-printing
- code, etc. The debug attribute conditionally compiles in code:
-
-
- class Foo
- {
- int a, b;
- debug:
- int flag;
- }
-
-
- Conditional Compilation means that if the code is not
- compiled in, it still must be syntactically correct, but no
- semantic checking or processing is done on it. No symbols are
- defined, no typechecking is done, no code is generated, no
- imports are imported.
-
- Various different debug builds can be built with a parameter to debug:
-
-
- debug(Integer) { } // add in debug code if debug level is >= Integer
- debug(identifier) { } // add in debug code if debug keyword is identifier
-
-
- These are presumably set by the command line as
- -debug=n and -debug=identifier.
- Version Attribute
-
-
- VersionAttribute:
- version ( Integer )
- version ( Identifier )
-
-
-
- The version attribute is very similar to the debug attribute,
- and in many ways is functionally interchangeable with it.
- The purpose of it, however, is different. While debug is for
- building debugging versions of a program, version is for using
- the same source to build multiple release versions.
-
- class Foo
- {
- int a, b;
-
- version(full)
- {
- int extrafunctionality()
- {
- ...
- return 1; // extra functionality is supported
- }
- }
- else // demo
- {
- int extrafunctionality()
- {
- return 0; // extra functionality is not supported
- }
- }
- }
-
-
- Various different version builds can be built with a parameter
- to version:
-
-
- version(n) { } // add in version code if version level is >= n
- version(identifier) { } // add in version code if version keyword is identifier
-
-
- These are presumably set by the command line as
- -version=n and -version=identifier.
-
-Static Assert
-
-
- StaticAssert:
- static assert ( Expression );
-
-
- Expression is evaluated at compile time, and converted
- to a boolean value. If the value is true, the static assert
- is ignored. If the value is false, an error diagnostic is issued
- and the compile fails.
-
- void foo()
- {
- if (0)
- {
- assert(0); // never trips
- static assert(0); // always trips
- }
- version (BAR)
- {
- static assert(0); // does not trip unless BAR is defined
- }
- }
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+
+Conditional Compilation
+
+ Conditional compilation is the process of selecting which
+ code to compile and which code to not compile.
+ (In C and C++, conditional compilation is done with the preprocessor
+ directives #if / #else / #endif.)
+
+
+ ConditionalDeclaration:
+ Condition DeclarationBlock
+ Condition DeclarationBlock else DeclarationBlock
+
+ DeclarationBlock:
+ Declaration
+ { Declarations }
+
+ Declarations:
+ Declaration
+ Declaration Declarations
+
+ ConditionalStatement:
+ Condition Statement
+ Condition Statement else Statement
+
+
+ If the Condition is satisfied, then the following
+ DeclarationBlock or Statement is compiled in.
+ If it is not satisfied, the DeclarationBlock or Statement
+ after the optional else is compiled in.
+
+ Condition:
+ VersionCondition
+ DebugCondition
+ StaticIfCondition
+ IfTypeCondition
+
+
+Version Condition
+
+ Versions enable multiple versions of a module to be implemented
+ with a single source file.
+
+ VersionCondition:
+ version ( Integer )
+ version ( Identifier )
+
+
+ The VersionCondition is satisfied if the Integer
+ is greater than or equal to the current version level,
+ or if Identifier matches a version identifier.
+
+
+
+ int k;
+ version (Demo) // compile in this code block for the demo version
+ { int i;
+ int k; // error, k already defined
+
+ i = 3;
+ }
+ x = i; // uses the i declared above
+
+
+
+ version (X86)
+ {
+ ... // implement custom inline assembler version
+ }
+ else
+ {
+ ... // use default, but slow, version
+ }
+
Version Specification
+
+
+ VersionSpecification
+ version = Identifier ;
+ version = Integer ;
+
+
+ The version specification makes it straightforward to group
+ a set of features under one major version, for example:
+
+
+
+
+ version (ProfessionalEdition)
+ {
+ version = FeatureA;
+ version = FeatureB;
+ version = FeatureC;
+ }
+ version (HomeEdition)
+ {
+ version = FeatureA;
+ }
+ ...
+ version (FeatureB)
+ {
+ ... implement Feature B ...
+ }
+
+
+
+ version (Foo)
+ {
+ int x;
+ }
+ version = Foo; // error, Foo already used
+
+
+
+ class Foo
+ {
+ int a, b;
+
+ version(full)
+ {
+ int extrafunctionality()
+ {
+ ...
+ return 1; // extra functionality is supported
+ }
+ }
+ else // demo
+ {
+ int extrafunctionality()
+ {
+ return 0; // extra functionality is not supported
+ }
+ }
+ }
+
+
+
+ version(n) { } // add in version code if version level is >= n
+ version(identifier) { } // add in version code if version keyword is identifier
+
Predefined Versions
+
+ Several environmental version identifiers and identifier
+ name spaces are predefined for consistent usage.
+ Version identifiers do not conflict
+ with other identifiers in the code, they are in a separate name space.
+ Predefined version identifiers are global, i.e. they apply to
+ all modules being compiled and imported.
+
+
+
+ Others will be added as they make sense and new implementations appear.
+
+
+
+
+ version(DigitalMars_funky_extension)
+ {
+ ...
+ }
+
Debug Condition
+
+ Two versions of programs are commonly built,
+ a release build and a debug build.
+ The debug build includes extra error checking code,
+ test harnesses, pretty-printing code, etc.
+ The debug statement conditionally compiles in its
+ statement body.
+ It is D's way of what in C is done
+ with #ifdef DEBUG / #endif pairs.
+
+
+ DebugCondition:
+ debug
+ debug ( Integer )
+ debug ( Identifier )
+
+
+ The debug condition is satisfied when the -debug switch is
+ thrown on the compiler.
+
+
+
+ class Foo
+ {
+ int a, b;
+ debug:
+ int flag;
+ }
+
Debug Specification
+
+
+ DebugSpecification
+ debug = Identifier ;
+ debug = Integer ;
+
+
+ Debug identifiers and levels are set either by the command line switch
+ -debug or by a DebugSpecification.
+
+
+
+ debug (foo) printf("Foo\n");
+ debug = foo; // error, foo used before set
+
+
+
+ debug(Integer) { } // add in debug code if debug level is >= Integer
+ debug(identifier) { } // add in debug code if debug keyword is identifier
+
Static If Condition
+
+
+ StaticIfCondition:
+ static if ( AssignExpression )
+
+
+ AssignExpression is implicitly converted to a boolean type,
+ and is evaluated at compile time.
+ The condition is satisfied if it evaluates to true.
+ It is not satisfied if it evaluates to false.
+
+
+
+ const int i = 3;
+ int j = 4;
+
+ static if (i == 3) // error, at module scope
+ int x;
+
+ class C
+ { const int k = 5;
+
+ static if (i == 3) // ok
+ int x;
+ else
+ long x;
+
+ static if (j == 3) // error, j is not a constant
+ int y;
+
+ static if (k == 5) // error, k is in current scope
+ int z;
+ }
+
+ template INT(int i)
+ {
+ static if (i == 32)
+ alias int INT;
+ else static if (i == 16)
+ alias short INT;
+ else
+ static assert(0); // not supported
+ }
+
+ INT!(32) a; // a is an int
+ INT!(16) b; // b is a short
+ INT!(17) c; // error, static assert trips
+
+
+
+Iftype Condition
+
+
+ IftypeCondition:
+ iftype ( Type : TypeSpecialization )
+ iftype ( Type Identifier )
+ iftype ( Type Identifier : TypeSpecialization )
+
+ TypeSpecialization:
+ Type
+
+
+ IftypeCondition is analogous to StaticIfCondition
+ except that it is for types rather than expressions.
+ There are three forms, corresponding to the three definitions above:
+
+
+
+
+
+
+
+
+ alias short bar;
+ int foo(bar x)
+ {
+ iftype (bar : int) // satisfied because short can be
+ // implicitly converted to int
+ printf("satisfied\n");
+ else
+ printf("not satisfied\n");
+ }
+
+
+
+ alias short bar;
+ int foo(bar x)
+ {
+ iftype (bar T)
+ alias T S;
+ else
+ alias long S;
+
+ writefln(typeid(S)); // prints "short"
+ }
+
+
+
+ alias short bar;
+ alias long* abc;
+ int foo(bar x, abc a)
+ {
+ iftype (bar T : int)
+ alias T S;
+ else
+ alias long S;
+
+ writefln(typeid(S)); // prints "int"
+
+ iftype (abc U : U*)
+ U u;
+
+ writefln(typeid(typeof(u)); // prints "long"
+ }
+
Static Assert
+
+
+ StaticAssert:
+ static assert ( Expression );
+
+
+ Expression is evaluated at compile time, and converted
+ to a boolean value. If the value is true, the static assert
+ is ignored. If the value is false, an error diagnostic is issued
+ and the compile fails.
+
+
+
+ void foo()
+ {
+ if (0)
+ {
+ assert(0); // never trips
+ static assert(0); // always trips
+ }
+ version (BAR)
+ {
+ }
+ else
+ {
+ static assert(0); // trips when version BAR is not defined
+ }
+ }
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
-
-Example: wc
-
-This program is the D version of the classic wc (wordcount) C program.
-It serves to demonstrate how to read files, slice arrays,
-and simple symbol table management with associative arrays.
-
-
-import std.file;
-
-int main (char[][] args)
-{
- int w_total;
- int l_total;
- int c_total;
-
- printf (" lines words bytes file\n");
- foreach (char[] arg; args[1 .. args.length])
- {
- char[] input;
- int w_cnt, l_cnt, c_cnt;
- int inword;
-
- input = cast(char[])std.file.read(arg);
-
- foreach (char c; input)
- {
- if (c == '\n')
- ++l_cnt;
- if (c != ' ')
- {
- if (!inword)
- {
- inword = 1;
- ++w_cnt;
- }
- }
- else
- inword = 0;
- ++c_cnt;
- }
- printf ("%8lu%8lu%8lu %.*s\n", l_cnt, w_cnt, c_cnt, arg);
- 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);
- }
- return 0;
-}
-
-
-Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright (c) 1999-2003 by Digital Mars, All Rights Reserved
+Last update Thu May 19 2005
+
+
+
+Example: wc
+
+This program is the D version of the classic wc (wordcount) C program.
+It serves to demonstrate how to read files, slice arrays,
+and simple symbol table management with associative arrays.
+
+
+
+
+import std.file;
+
+int main (char[][] args)
+{
+ int w_total;
+ int l_total;
+ int c_total;
+
+ printf (" lines words bytes file\n");
+ foreach (char[] arg; args[1 .. args.length])
+ {
+ char[] input;
+ int w_cnt, l_cnt, c_cnt;
+ int inword;
+
+ input = cast(char[])std.file.read(arg);
+
+ foreach (char c; input)
+ {
+ if (c == '\n')
+ ++l_cnt;
+ if (c != ' ')
+ {
+ if (!inword)
+ {
+ inword = 1;
+ ++w_cnt;
+ }
+ }
+ else
+ inword = 0;
+ ++c_cnt;
+ }
+ printf ("%8lu%8lu%8lu %.*s\n", l_cnt, w_cnt, c_cnt, arg);
+ 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);
+ }
+ return 0;
+}
+
Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved
Last update Jan 26, 2005
-
-
-D for Win32
-
- This describes the D implementation for 32 bit Windows systems. Naturally,
- Windows specific D features are not portable to other platforms.
-
- #include <windows.h>
-
- of C, in D there is:
-
- import std.c.windows.windows;
-
-
-
-Calling Conventions
-
- In C, the Windows API calling conventions are __stdcall. In D,
- it is simply:
-
-
- extern (Windows)
- {
- ... function declarations ...
- }
-
-
- The Windows linkage attribute sets both the calling convention
- and the name mangling scheme to be compatible with Windows.
-
- export void func(int foo);
-
-
- If no function body is given, it's imported. If a function body
- is given, it's exported.
-
-Windows Executables
-
- Windows GUI applications can be written with D.
- A sample such can be found in \dmd\samples\d\winsamp.d
-
-
-
-
-
-
-import std.c.windows.windows;
-
-extern (C) void gc_init();
-extern (C) void gc_term();
-extern (C) void _minit();
-extern (C) void _moduleCtor();
-extern (C) void _moduleUnitTests();
-
-extern (Windows)
-int WinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPSTR lpCmdLine,
- int nCmdShow)
-{
- int result;
-
- gc_init(); // initialize garbage collector
- _minit(); // initialize module constructor table
-
- try
- {
- _moduleCtor(); // call module constructors
- _moduleUnitTests(); // run unit tests (optional)
-
- result = myWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
- }
-
- catch (Object o) // catch any uncaught exceptions
- {
- MessageBoxA(null, cast(char *)o.toString(), "Error",
- MB_OK | MB_ICONEXCLAMATION);
- result = 0; // failed
- }
-
- gc_term(); // run finalizers; terminate garbage collector
- return result;
-}
-
-int myWinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPSTR lpCmdLine,
- int nCmdShow)
-{
- ... insert user code here ...
-}
-
-
- The myWinMain() function is where the user code goes, the
- rest of WinMain is boilerplate to initialize and shut down
- the D runtime system.
-
-
-EXETYPE NT
-SUBSYSTEM WINDOWS
-
- Without those, Win32 will open a text console window whenever
- the application is run.
-
- Feedback and Comments
-
- Add feedback and comments regarding this
- page.
-
-
Copyright (c) 1999-2005 by Digital Mars, All Rights Reserved
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Last update Thu May 19 2005
+
+
+
+D for Win32
+
+ This describes the D implementation for 32 bit Windows systems. Naturally,
+ Windows specific D features are not portable to other platforms.
+
+
+
+ #include <windows.h>
+
+
+
+ import std.c.windows.windows;
+
Calling Conventions
+
+ In C, the Windows API calling conventions are __stdcall. In D,
+ it is simply:
+
+
+
+
+ extern (Windows)
+ {
+ ... function declarations ...
+ }
+
+
+
+ export void func(int foo);
+
Windows Executables
+
+ Windows GUI applications can be written with D.
+ A sample such can be found in \dmd\samples\d\winsamp.d
+
+
+
+
+
+
+
+import std.c.windows.windows;
+
+extern (C) void gc_init();
+extern (C) void gc_term();
+extern (C) void _minit();
+extern (C) void _moduleCtor();
+extern (C) void _moduleUnitTests();
+
+extern (Windows)
+int WinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ int result;
+
+ gc_init(); // initialize garbage collector
+ _minit(); // initialize module constructor table
+
+ try
+ {
+ _moduleCtor(); // call module constructors
+ _moduleUnitTests(); // run unit tests (optional)
+
+ result = myWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
+ }
+
+ catch (Object o) // catch any uncaught exceptions
+ {
+ MessageBoxA(null, cast(char *)o.toString(), "Error",
+ MB_OK | MB_ICONEXCLAMATION);
+ result = 0; // failed
+ }
+
+ gc_term(); // run finalizers; terminate garbage collector
+ return result;
+}
+
+int myWinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ ... insert user code here ...
+}
+
+EXETYPE NT
+SUBSYSTEM WINDOWS
+
+ Without those, Win32 will open a text console window whenever
+ the application is run.
+
+ Feedback and Comments
+
+ Add feedback and comments regarding this
+ page.
+
+
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved