Perl Best Practices by Damian Conway This errata page lists errors outstanding in the most recent printing. If you have technical questions or error reports, you can send them to booktech@oreilly.com. Please specify the printing date of your copy. This page was updated March 21, 2007. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification Confirmed errors: (xv) 4th paragraph, end of first sentence; "...ivory-tower theories on how code ought be created." Should be: "...ought to be created." (6) 4th paragraph, 1st sentence; "But remember that each of piece of advice" should be: "But remember that each piece of advice" (24) 1st paragraph; "Note, however, that the contents of paragraphs..." replace "contents" with "comments" {35} Code snippet, 3rd line from bottom; -wbb="% + - * / x != == >= <= =~ < > | & >= < = **= += *= &= <<= &&= -= should be: -wbb="% + - * / x != == >= <= =~ < > | & **= += *= &= <<= &&= -= (38) Code snippet in middle of page, 3rd line; my $estimated_nett_worth; should be: my $estimated_net_worth; (46) Footnote; In parenthetical comment, 'mby' should be 'myb' ('maybe', disemvoweled) {47} first code listing; The expression $connection_Mbps = get_bitrate() / 10e6; should be $connection_Mbps = get_bitrate() / 1e6; (54) 3rd code example; The example: $escape_seq = "\127\006\030Z"; # DEL-ACK-CAN-Z should be: $escape_seq = "\177\006\030Z"; # DEL-ACK-CAN-Z {57} 1st code snippet; The statements: use constant ( DEAR => 'Greetings to you,', SINCERELY => 'May Heaven guard you from all misfortune,', ); should be: use constant { DEAR => 'Greetings to you,', SINCERELY => 'May Heaven guard you from all misfortune,', }; (That is, braces instead of parentheses). (58) 2nd last paragraph; Change: If you decide not use the Readonly module ... to: If you decide not to use the Readonly module ... (59) 2nd line; replace atomic weight values by atomic number values {66} Fourth listing; Instead of: $text = format_text(src=>$raw_text, margins=>[1,62], justify=>'left'); it should definitely read: $text = format_text({ src=>$raw_text, margins=>[1,62], justify=>'left' }); [72] Last paragraph; The lines: Readonly my %IS_EXIT_WORD => map { ($_ => 1) } qw( q quit bye exit stop done last finish aurevoir ); Should read: Readonly my %IS_EXIT_WORD = map { ($_ => 1) } qw( q quit bye exit stop done last finish aurevoir ); (81) Halfway down page, first sentence; The problems described earlier under "Localization can also crop up... should be: The problems described earlier under "Localization" can also crop up... ^ (88) 1st, 3rd and 4th code listing; the word "prepenultimate" should be "antepenultimate" (115) 2nd indented paragraph ("The implicit $_ successively holds..."); "...then see if the resulting file exists. If it does, then..." should be: "...then see if the resulting file exists. If it doesn't, then..." ^^^ (137) Near bottom where describing macro for vim; iab papp ^]:r ... should be iab papp ^[:r ... {150} First code example; The line "Use Digest::SHA qw( sha512 );" should have "use" in all lower case. {157} Last code example; $RECORD_SEPARATOR should properly be named $FIELD_SEPARATOR (especially vis-à-vis $FIELD_COUNT) {157} First full code listing; the entry for $RECORD_LAYOUT{ID_last}: ID_last => '@21 C6 @0 C10 @12 C8 should be ID_last => '@21 A6 @0 A10 @12 A8 {158} 1st code example, last line; if $unexpected_data; should be: if defined $unexpected_data; (161) String Evaluations section; end of next to last line 1st paragraph (below code); "expected processing delays," should be "unexpected processing delays," (166) Next to last paragraph; ...no need for (expensive) hash loop-ups inside the loop. should be: ...no need for (expensive) hash look-ups inside the loop. ^ (172) First line of code in 'reduce' paragraph; $overall_probablity should be: $overall_probability (177) mid of page, in second (not recommended) codefragment; ... # Maybe the same (if currobj() already declared), should be ... # Maybe the same (if curr_obj() already declared), ^ (198) source fragment at top of page; return $num if $prev_found; should be return $num if $prev_odd_found; ^^^^ (205) footnote; Replace Chapter 2 by Chapter 3 {207} First code example; Keep the bad practice (2-arg open) for pedagogical purposes but remove the bug (double dollar). Replace open my $active, "$ACTIVE_LOG" or croak "Can't open '$$ACTIVE_LOG': $OS_ERROR"; by open my $active, "$ACTIVE_LOG" or croak "Can't open '$ACTIVE_LOG': $OS_ERROR"; (215) third paragraph from bottom; "slurp()" shouldn't be line-broken between the parentheses [242] 1st paragraph; Regexp::Autoflags does not exist in CPAN. Regexp::Autoflags should be: Regexp::DefaultFlags {259} example code, 6th-from-last line; change: if ($word =~ m/ ($has_irregular_plural) /xms) { to: if ($word =~ m/\A ($has_irregular_plural) \z/xms) { (275) 2nd paragraph after Example 13-1, 3rd sentence; "loader_header_from()" should be "load_header_from()". (284) 3rd line; The 3rd line reads: ... it can still better to use croak(): which probably should read: ... it can still be better to use croak(): [289] Second code block; eval { return get_next_line() }; should be replaced with: my $next_line = eval { get_next_line() }; return $next_line if !$EVAL_ERROR; [290] 2nd paragraph, 5th line; tion object ($EVAL_ERROR->get_handle()) and seeks it back should be: tion object ($EVAL_ERROR->handle()) and seeks it back {296} first code snippet; Change the line: X::EOF => { to: 'X::EOF' => { {298} Second code listing; The last line of code in the second code listing: seek $exception->fh(), 0, 0; should be: seek $exception->handle(), 0, 0; to match the last line of code in the first code listing of that page. (339) last line; The two occurrences of "=>" should each be "->" . So the line should be: = exists $arg_ref->{vagueness} ? $arg_ref->{vagueness} : 1; In fact, it is correct in the example file: ./code/ch15/Ch15.034_Best_Ex15.5 {352} code of the Bit::String class; There is a subtle bug in the code of the Bit::String class shown on page 352. Specifically, the line: $bitset_of{ident $new_object} = pack $BIT_PACKING, map {$_ ? 1 : 0} @{$arg_ref->{bits}}; should be: $bitset_of{ident $new_object} = pack $BIT_PACKING, join $EMPTY_STR, map {$_ ? 1 : 0} @{$arg_ref->{bits}}; [367] 4th paragraph, 2nd sentence; "...at the start of the destructor..." change "destructor" to "constructor" (371) 2nd paragraph (under Base Class Initialization section); Second sentence reads (underline emphasis mine): "If two or more classes in the _name_ hierarchy do happen to have attributes of the same name, the constructor will need two or more initializers with the _name_ key -- which a single hash can't provide." It should read: "If two or more classes in the _same_ hierarchy do happen to have attributes of the same name, the constructor will need two or more initializers with the _same_ key -- which a single hash can't provide." (374) paragraph below second code sample (middle of page); "Class::Std::Utils" is incorrectly written as "Class::Std::Util" in the paragraph in the middle of the page (just above the extract_initializers_from() function). (386) last paragraph; There is an asterisk on the 3rd line of the last paragraph of page 385, but the corresponding footnote is on the next page. (393) last line on page; The footnote referenced is on the next page. (416) 3rd paragraph; ("to" instead of "do") "Better still, Module::Starter has a simple plug-in architecture that allows you do specify how it creates each new module..." should read: "Better still, Module::Starter has a simple plug-in architecture that allows you to specify how it creates each new module..." (424) 2nd to last line; "... your /t directory ..." should be "... your t/ directory ..." (430) Code after 2nd paragraph line 11 of code; sub dump_a should be sub dump_at as referenced in 3rd paragraph line 2; (430) paragraph after code block; "use strict never gets the change to" replace "change" with "chance" [443] Whole page (Round.pm), Round.xs; To work, it should read (tested on Mandriva Linux, perl-5.8.7) : 1: perl -pi -e 's/rounded/round/g' Round.xs rounded.pl 2: perl -pi -e 's/^@EXPORT/our @EXPORT/' Round.pm to avoid : Global symbol "@EXPORT" requires explicit package name at /usr/lib/perl5/site_perl/5.8.7/i386-linux/Round.pm line 6. 3: perl -pi -e 's/res/RETVAL/g' Round.xs to avoid : Error: OUTPUT res not an argument in Round.xs, line 15 Please specify prototyping behavior for Round.xs (see perlxs manual) The correct code follows : > cat Round.pm package Round; use strict; use warnings; use base qw( Exporter DynaLoader ); our $VERSION = '0.01'; our @EXPORT = qw( round ); bootstrap Round $VERSION; 1; __END__ > cat rounded.pl use Round; use IO::Prompt; while (my $num = prompt -num => 'Enter a number: ') { print round($num), "\n"; } > cat Round.xs #include "EXTERN.h" #include "perl.h" #include "XSUB.h" MODULE = Round PACKAGE = Round int round(arg) double arg CODE: /* Round towards zero... */ if (arg > 0.0) { RETVAL = floor(arg + 0.5); } else if (arg < 0.0) { RETVAL = ceil(arg - 0.5); } else { RETVAL = 0; } OUTPUT: RETVAL (447) end of the code section at top of page; the last two lines:
should be:
(451) first line of "Ties" section; "behaviour any type of variable" should read "behaviour of any type of variable" (465) last paragraph; ...summarize the results with dproffpp... -> dprofpp {467} Last code block; The regular expression reads: m{\A Name: \s+ ([^\N]+) ; \s+ \n? \z}xms The [^\N] above should be [^\n] (489) Readonly module; Change the line: Readonly Creates read-only scalars, arrays, and hashes (see Chapter 14) 1.03 or later to: Readonly Creates read-only scalars, arrays, and hashes (see Chapter 4) 1.03 or later