TDPL Errata
The list below is created by readers and D users like you and maintained by the book's author.
All code samples can be downloaded off here (also refer to the related announcement). Get individual examples or all.zip to get them all. The examples that currently don't work as expected with the reference implementation are in the "shouldwork" subdirectory.
To add entries, please contact Andrei. Don't forget to specify the printing, which can be seen at the bottom of the copyright page (the one just before Contents) and reads like "First printing, May 2010".
|
Page | Current text | Correction | Submitter | |
|---|---|---|---|---|
| xxv | 1 | justfy | justify | Björn Fahller |
| 5 | 1 | %i for integers | %d for integers | Andrei Alexandrescu (on behalf of Roel) |
| 6 | 1 | the code sample above also introduced the if statement | there is no if statement above | Benjamin Shropshire |
| 8 | 1 | the large example should use size_t instead of uint | Andrei Alexandrescu (on behalf of bearophile) | |
| 8 | 1 | The use of dictionary[word] in the dictionary code sample does not compile with dmd 2.050+. | Instead, the code should use dictionary[word.idup] or dictionary[to!string(word)] to convert word of type char[] to type string, which is required by the dictionary. Also, splitter is in module std.algorithm, not std.string. |
Andrei Alexandrescu (on behalf of Caligo and Chris Saunders) |
| 8 | 1 | foreach(word; split(strip(line))) | Should be foreach(word; splitter(strip(line))) for consistency with the example on page 8 and for better efficiency. | Michal Mocny |
| 8 | 1 | The example doesn't compile on 64-bit because size_t is not convertible to uint. | Change definition of dictionary from uint[string] to size_t[string], or cast newID to uint. | Jonathan M Davis |
| 12 | 1 | Speaking of state, let's write a recursive implementation of binarySearch that doesn't reassign index at all: | Replace "index" with "input" | Geert Fannes |
| 12 | 1 | if ( mid > value ) return binarySearch( input[0 .. i] ); if ( mid < value ) return binarySearch( input[i + 1 .. $] ); |
if ( mid > value ) return binarySearch( input[0 .. i], value ); if ( mid < value ) return binarySearch( input[i + 1..$], value ); |
Byron Heads |
| 12 | 1 | the compiler modifies the argument | the compiler modifies the arguments | Andrei Alexandrescu |
| 13 | 1 | Doesn't mention the need to import std.algorithm to gain access to the sort function. | 'Add `, std.algorithm` to the first line.' | Bernard Helyer |
| 16 | 1 | The last paragraph in the code example is not added |
Add right after the loop: if (!currentParagraph.empty) addParagraph(currentParagraph, info); |
Tim Marston |
| 17 | 1 | better makes a copy of it | better make a copy of it | Philip Zigoris |
| 18 | 1 | Text mentions std.algorithm find, but code uses haystack.find(needle). | At this point the reader has not been explained that both forms work. | Michal Mocny |
| 22 | 1 | stats example will not compile and run as is | readf should be stdin.readf, and need to add a try/catch for std.conv.ConvError. | Dan Renfro |
| 22 | 1 | Object.factory.Object four lines from the bottom of the page. | There is confusion between the use of "." in code and typographically. | Michal Mocny |
| 22 | 1 | The bottom of page 22 and the top of page 23 refer to Max, which hasn't been yet defined. | For clarity the references should be changed to Min. | Thanate Dhirasakdanon |
| 23 | 1 | aside from a slight change in accumulate, everything is exactly the same | The member needs to be initialized to -double.max (and possibly renamed) | Eitan Frachtenberg |
| 26 | 1 | In D, slicing could never occur. | This should probably be: In D, C++'s damaging slicing could never occur. |
Andrej Mitrovic |
|
31 |
1 | List of keywords | Keywords immutable, lazy, pure, nothrow, and shared are missing (more detail) | Jonathan M Davis |
| 32 | 1 | Integral literals | Octal literals have been removed from the language and replaced with a standard library facility std.conv.octal. | Vladimir Panteleev |
| 35 | 1 | String WYSIWYG literals | Delimited WYSIWYG string literals are missing | Vladimir Panteleev |
| 36 | 1 | The ASCII values for backspace, formfeed, line feed and carriage return seem to be given in octal. | Jos | |
| 39 | 1 | you can suffix a string literal with c, w or d, which, similar to the homonym character literal suffixes, force the type. | you can suffix a string literal with c, w or d, which, force the type. char literals make no reference to suffixes | Benjamin Shropshire |
| 44 | 1 | Figure 2.3: Implicit integral conversions. | The figure shows both integrals and floating-point types. | Geert Fannes |
| 49 | 1 | Bullet 4 mentions "A kind is one of the following keywords: ..." and is missing "return" while it does appear in table 2.4. Also, the order of keywords mentioned and table listing is not the same (is there any ordering/grouping?). | Michal Mocny | |
| 49 | 1 | "A kind is one of..." | "A kind can be one of..." There also seem to be a few mismatches with the online documentation, e.g. the inout keyword. | Andreas Guðmundsson |
| 50 | 1 | "evaluating postincrement or postdecrement increments" | "evaluating postincrement or postdecrement modifies" | Eli Sternheim |
| 50 | 1 | If the indexing expression is on the left-hand side of an assignment operation (e.g., arr[i] = e) and a is an associative array | arr is an associative array, not "a" | Andrej Mitrovic |
| 50 | 1 | Section 2.3.5.4. The text implies that "arr[i] is the ith (zero-based) element of... associative array arr", which is incorrect. | Rephrase | Michal Mocny |
| 53 | 1 | (see the definition of nonzero 46) | "on page" should be inserted | Geert Fannes |
| 56 | 1 | Section 2.3.11 In the first code block table["hello"] = 0; should be = 1; | Michal Mocny | |
| 57 | 1 | a is c && writefln("Indeed... not the same"); | a is c && writeln("Indeed... not the same"); | Andrej Mitrovic |
| 60 | 1 | 1. If a and b have the same type, ... 2. else if a and b are integrals, ... 6. else try implicitly converting a to b's type and b to a's type; | 1. If b and c have the same type, ... 2. else if b and c are integrals, ... 6. else try implicitly converting b to c's type and c to b's type; | Cassio Neri |
| 67 | 1 | a colon present by itself is not a statement | a semicolon present by itself is not a statement | Andrew C Edwards |
| 68 | 1 | 2nd example on page | Text says "If you instead want to bind the else to the first if..." but the braces in the example that follows bind it to the second if. | Jonathan M Davis |
| 68 | 1 | The enum syntax is used without having been introduced. | Michal Mocny | |
| 68 | 1 | In the second code block, the last angle bracket is misplaced and should come before the else. | Geert Fannes | |
| 70 | 1 | ...for example, we could define numeric globally ... | ...for example, we could define Numeric globally ... | Karim Naqvi |
| 75 | 1 | Chapter 12 will deal with the latter case, | Chapter 12 will deal with the last case, | Andrew Talbot |
| 76 | 1 | ref counts on and exact match of representation | ref counts on an exact match of representation | Jonathan M Davis |
| 76 | 1 | ...ref counts on and exact match... | Replace "and" with "an" | Geert Fannes |
| 81 | 1 | Should explain what happens with locals hidden by the "with" statement. | Michal Mocny | |
| 82 | 1 | All controlled statements must be block statements; that is, they must be enclosed by braces. | The statement is incorrect and should be removed. C++ has that restriction. D does not. (more detail) | Jonathan M Davis |
| 82 | 1 | The first type that is or a class derived from it | The first type that is or a superclass of it | Simen Kjaeraas |
| 82 | 1 | strings known during compilation in D expressions | strings known during compilation into D expressions | Russel Winder |
| 87 | 1 | The lowering of scope(failure) is almost identical to that of scope(exit) | The lowering of scope(failure) is almost identical to that of scope(success) | Eitan Frachtenberg |
| 89 | 1 | Bibentry [12] links to D 1.0 assembler. | Michal Mocny | |
| 94 | 1 | After the code block foreach ( ref ... ), you write "The ref informs the compiler that we want to reflect assignment...". I think the word "reflect" is a poor work choice, since, although grammatically correct, one could easily deduce that ref stands for "reflect", and don't think that is correct. | Michal Mocny | |
| 103 | 1 | so write "no palindrome" and bail out. | so write "not palindrome" and bail out. | Andrew C Edwards |
| 103 | 1 | Only if all tests succeed and args got shorter than two elements (the program considers arrays of zero or one element palindromes), the program prints "palindrome" and exits. | Only if all tests succeed and args get shorter than two elements (the program considers arrays of zero or one element palindromes), [will/does] the program print "palindrome" and exit. | Andrew C Edwards |
| 106 | 1 | auto array = new int[10] ; array. length += 1000; // Grow |
auto array = new int[10] ; array. length += 1000; // Grow |
Roberto C. B. Ballona |
| 114 | 1 | Second paragraph: "[associative arrays]... possible to map a value of a different type..." I would change that to "of another type" since types need not necessarily be different. | Michal Mocny | |
| 114 | 1 | Section 4.4.1 first paragraph, last sentence "The type of aa.length is size_t" -- this statement was just said in the first sentence. | Michal Mocny | |
| 116 | 1 | last line of example 1: assert(a2["Sam"] == 3.5; // versa | should read: assert(a1["Sam"] == 3.5; // versa | Andrew C Edwards |
| 117 | 1 | it is preferable to iterate with foreach instead of fetching keys of values | it is preferable to iterate with foreach instead of fetching keys or values | Alix Pexton |
| 124 | 1 | [H][a][l][l][å][,][ ][V][ä][r][d][!] | [H][a][l][l][å][,][ ][V][ä][r][l][d][!] (värd means worth, not world) | Simen Kjaeraas |
| 124 | 1 | As such, the pointer does not have information on whether the chunk starts and ends. | Please rephrase. | Geert Fannes |
| 125 | 1 | "of an array with a.ptr" | "of an array arr with arr.ptr" | Eli Sternheim |
| 129 | 1 | Table 4.5 does not include a.byKey() and a.byValue(). | Alix Pexton | |
| 143 | 1 | The first unittest fails due to representational differences between float and double. | Use e.g. int and long | Abid H. Mujtaba |
| 144 | 1 | Three equally specialized functions: either could be called | Three equally specialized functions: each could be called | Andrew Talbot |
| 146 | 1 | The transmogrify(uint) overload in calvin.d is ... | The transmogrify(uint) overload in hobbes.d is ... | Cassio Neri |
| 148 | 1 | First code snipped is missing an import | import hobbes; | Andrej Mitrovic |
| 148 | 1 | Second code snippet: missing alias to susie. The code must alias all modules with overloads. | alias susie.transmogrify transmogrify; | Andrej Mitrovic |
| 161 | 1 | to!string(arg0), to!string(arg1), to!string(arg2), to!string(arg3) | to!string(a0), to!string(a1), to!string(a2), to!string(a3) | Andrew C Edwards |
| 162 | 1 | forwards four, not two, arguments to write | forwards four, not three, arguments to write
(?) |
Roberto C. B. Ballona |
| 163 | 1 | Last paragraph before 5.10.2.2 | Please insert explanation on why tuples do not have literals. | Geert Fannes |
| 174 | 1 | regular variables for m, a and b. | regular variables for m, a and c. | Andrew Talbot |
| 179 | 1 | The third box from the top seems like an internal unit test for the example above it (use of __traits(compiles, …)). | David Nadlinger | |
| 181 | 1 | assert(t.a == 0.4 && isnan(t.b)); | assert(t.a == 0.4 && isNaN(t.b)); | Andrew Talbot |
| 185 | 1 | The code below efficiently initializes a fixed size array with 0.0, 0.1, 0.2,..., 1.28: | The code below efficiently initializes a fixed size array with 0.0, 0.1, 0.2,..., 12.7: | Alix Pexton |
| 188 | 1 | Last line in the first example: assert(b1.data is null); | assert(b1.data !is null); | Andrej Mitrovic |
| 189 | 1 | initialization orderHere's how the ordering works. | Here's how the ordering works. (can't see where the extra words originated) | Alix Pexton |
| 189 | 1 | MA imports MB. Then A's static class constructors run before B's.
MB imports MA. Then B's static class constructors run before A's. |
MA imports MB. Then B's static class constructors run before A's.
MB imports MA. Then A's static class constructors run before B's. |
Andrej Mitrovic |
| 191 | 1 | auto color = c.bgColor(); // call a contact method | auto color = c.bgColor(); // call a friend method | Andrej Mitrovic |
| 191 | 1 | (in this case, currentBgColor) | currentReminder is also a state variable introduced by Friend. | Geert Fannes |
| 196 | 1 | being scope inside a class | being scope inside a class | Andrew Talbot |
| 199 | 1 | class PostUltimateWidget : Widget { ... } | class PostUltimateWidget : UltimateWidget { ... } | Alix Pexton |
| 208 | 1 | Last line of example 2: return text == that.text; | return text == that2.text; | Andrej Mitrovic |
| 208 | 1 | tw == w && w != tw breaks reflexivity | In fact it breaks symmetry. | Jens Mueller |
| 215 | 1 | Last line of example 2: override void doUntransmogrify() { ... } | This method does not override any interface methods, change to: void doUntransmogrify() { ... } | Andrej Mitrovic |
| 216 | 1 | enforce() is undefined | Missing import std.exception; | Andrej Mitrovic |
| 217 | 1 | Example 2 | BrokenInTwoWays should implement Transmogrifier. | Simen Kjaeraas |
| 219 | 1 | class Rectangle : RectangularShape | The Rectangle class has already been defined as the Base class for all the derived classes in the example. A different name should be used for the class that implements RectangularShape. | Andrej Mitrovic |
| 228 | 1 | Then we define Sprite3 to implement ObservantActor and VisualActor: | Then we define Sprite3 to implement HyperObservantActor and VisualActor: | Alix Pexton |
| 234 | 1 | The discussion of Parameterized Classes and Interfaces doesn't mention anywhere the need to import std.array to gain access to the empty, back, and popBack functions as used in StackImpl. | Add std.array; to the first line. | Andrew C Edwards |
| 235 | 1 | Java and C# use heterogeneous translation for their parametrized types. | As far as I know Java uses homogeneous translation. The Integer in LinkedList is erased, and LinkedList doesn't even compile. | Enrico Kravina |
| 248 | 1 | …, again this(this) is invoked for the field w of field w2. | …, again this(this) is invoked for the field w1 of field w2. | David Nadlinger |
| 248 | 1 | // this(this) called for b.w | // this(this) called for b.w1 | Andrej Mitrovic |
| 249 | 1 | // this(this) for d.w2.w | // this(this) for d.w2.w1 | Andrej Mitrovic |
| 263 | 1 | First code example assumes that int.sizeof == size_t.sizeof | Make c of type size_t or change the last assert in fun. (Beware of alignment issues, too.) |
Timon Gehr |
| 267 | 1 | Figure 7.2 | Hatched area is barely visible. | Geert Fannes |
| 267 | 1 | "hashed areas", "hashed bytes" | "hatched areas", "hatched bytes" | Andrew Talbot |
| 270 | 1 | specify the desired initializer in brackets | specify the desired initializer in braces | Andrew Talbot |
| 271 | 1 | many uses of union actually use | sounds awkward, rephrase | Andrew Talbot |
| 271 | 1 | manipulation | manipulations | Andrew Talbot |
| 272 | 1 | Tag._void | Tag._tvoid | Jonathan Amsterdam |
| 273 | 1 | void f(ref double x) | void fun(ref double x) | Andrej Mitrovic |
| 279 | 1 | struct /* or class */ Select2(bool cond, T1, T2) { // Or class | struct Select2(bool cond, T1, T2) { // Or class | Alix Pexton |
| 288 | 1 | immutable expresses absolute, context-dependent immutability. | immutable expresses absolute, context-independent immutability. | Jonathan M Davis |
| 288 | 1 | immutable expresses absolute, context-dependent immutability | replace "dependent" with "independent" | Geert Fannes |
| 289 | 1 | missing closing parenthesis: static assert(is(typeof(origin.x) == immutable(int)); | static assert(is(typeof(origin.x) == immutable(int))); | Andrej Mitrovic |
| 290 | 1 | ds[1] = 4.5; // ? | ds.payload[1] = 4.5; // ? | Andrej Mitrovic |
| 307 | 1 | § 9.4 discussed nothrow functions | § 5.11.2 discussed nothrow functions | Alix Pexton |
| 309 | 1 | catch Exception e, while e = e.next != null | catch Throwable e, while e = e.next !is null | Andrej Mitrovic |
| 309 | 1 | code: import std.contracts, throw new CustomException("fun", x); | import std.exception, throw new CustomException("x is less than 0: ", "fun", x); | Andrej Mitrovic |
| 318 | 1 | throw new CustomException("fun", x); | throw new CustomException("Negative value ", "fun", x); | Michal Mocny |
| 325 | 1 | D defines such a function in module std.contracts | D defines such a function in module std.exception | Andrej Mitrovic |
| 326 | 1 | import std.contracts; | import std.exception; | Andrej Mitrovic |
| 327 | 1 | ..standard library function std.contracts.enforce(false), import std.contracts | ..standard library function std.exception.enforce(false), import std.exception | Andrej Mitrovic |
| 330 | 1 | // Require str | // Require spec | Jonathan Amsterdam |
| 335 | 1 | void push (T value) in { assert(!empty); } | void push (T value) | Alix Pexton |
| 336 | 1 | final void push (T value) { enforce(!empty); pushImpl(value); enforce(value == topImpl()); } | final void push (T value) { pushImpl(value); enforce(value == topImpl()); } | Alix Pexton |
| 338 | 1 | In the enumeration of the items that a module may start with, comments are missing. | A module may start with a comment which has '/' as its first character (that character, being ASCII, doesn't affect adversely the autodetection process). | Vladimir Panteleev |
| 340 | 1 | importThe order of importing modules is irrelevant. | The order of importing modules is irrelevant. | Alix Pexton |
| 357 | 1 | else if (info.dwMajorVerson == 6 && info.dwMinorVersion == 0) { winVersion = WinVersion.preVista; } else { winVersion = WinVersion.preVista; | else if (info.dwMajorVerson == 6 && info.dwMinorVersion == 0) { winVersion = WinVersion.vista; } else { winVersion = WinVersion.postVista; | Alix Pexton |
| 357 | 1 | The initialization of OSVERSIONINFOEX with a constant is confusing. | Michal Mocny | |
| 356 | 1 | "entire applications may be written entirely in SafeD." | "entire applications may be written in SafeD." | Eli Sternheim |
| 360 | 1 | Using PreFinalRelease is correct, but it would be nice to replace it with FinalRelease to integrate with the previous example. | Andrew Talbot | |
| 361 | 1 | Attempting to set a version in both the command line and a source file is, again, in error. | Attempting to set a version in both the command line and a source file is, again, an error. | Alix Pexton |
| 361 | 1 | No mention of the global debug flag. | Andrei Alexandrescu (on behalf of JRM) | |
| 361 | 1 | The debug was defined | The debug declaration was defined | Jonathan Amsterdam |
| 362 | 1 | std.contracts in the standard modules summary table | This should be replaced with std.exception | Andrej Mitrovic |
| 368 | 1 | Missing semicolons in two opUnary methods | return CheckedInt(mixin(op ~ "value;")); mixin(op ~ "value;"); | Andrej Mitrovic |
| 368 | 1 | Unary "-" should throw on int.min | Timon Gehr | |
| 372 | 1 | Broken return statements in opBinary "Addition", "Subtraction" and "Multiplication" | All three should be fixed with: return CheckedInt(result); | Andrej Mitrovic |
| 379 | 1 | The method names substitute "slice" for "array" throughout | Replace "array" with "index" | Geert Fannes |
| 382 | 1 | inorder traversal of the tree | preorder traversal of the tree | Eric Lawless |
| 383 | 1 | // Calls object.opApply(k, v) | Comment is mistaken because opApply passes a delegate, too. | Michal Mocny |
| 384 | 1 | static if (op == "+") { return opSubtract(rhs); } | static if (op == "-") { return opSubtract(rhs); } | Eric Lawless |
| 386 | 1 | a.opDispatch!"do_something_cool"(5, 6) has a trailing quote that needs to be removed. | By the way, opDispatch is ridiculously cool. | Michal Mocny |
| 387 | 1 |
Variant opDispatch(string m, Args)(Args args...) { |
should have the "..." in the variadic list: Variant opDispatch(string m, Args...)(Args args) { |
|
| 387 | 1 |
Variant(Dynamic, Variant[]) { |
The "delegate" keyword is required, and the "..." must be present in the signature. delegate Variant(Dynamic, Variant[]...) { |
|
| 393 | 1 | Also, the speed gap between processing elements and memory is also increasing. | "also" occurs twice | Eli Sternheim |
| 401 | 1 | Main thread: 999 \ Secondary thread: 999 | Main thread: 99 \ Secondary thread: 99 | Andrew Talbot |
| 401 | 1 | The example starting at the bottom of page 401 needs to import std.exception. Also, on dmd 2.051 the example throws an exception at runtime "std.concurrency.MessageMismatch: Unexpected message type" after printing all messages. | Martin Waite | |
| 406 | 1 | The example doesn't need std.algorithm. | Andrew Talbot | |
| 406 | 1 | foreach (immutable(ubyte)[] buffer; stdin.byChunk(bufferSize)) send(tid, buffer); | foreach (buffer; stdin.byChunk(bufferSize)) send(tid, buffer.idup) | Andrew Talbot |
| 407 | 1 | tgt.write(buffer); | stdout.write(buffer); | Andrew Talbot |
| 410 | 1 | // Inside std.concurrency void setMaxMailboxSize(Tid tid, size_t messages, bool(Tid) onCrowdingDoThis); |
// Inside std.concurrency void setMaxMailboxSize(Tid tid, size_t messages, bool function(Tid) onCrowdingDoThis); |
Jos van Uden |
| 413 | 1 | Anyway, real is meant mostly for high-precision temporary results and not for data interchange, so it makes little sense to want to share it anyway. | "Anyway" occurs twice | Eli Sternheim |
| 418 | 1 | For consistency with the example on page 415, balance() should be a property in the example at the bottom of this page, too. | Andrew Talbot | |
| 419 | 1 | no address of a field can escape a synchronized address. | no address of a field can escape a synchronized (class/object/method/...). | Alix Pexton |
| 419 | 1 | There are shared classes and shared structs, and then synchronized classes. | Could there be synchronized structs? | Michal Mocny |
| 422 | 1 | setMutex | setSameMutex | Jonathan Amsterdam |
| 449 | 1 | "import, static" is listed as appearing on page 347. | In fact it appears on page 345. | Jonathan M. Davis |
Contact Andrei to add a new erratum.