Beginning programmers face a great learning curve. Beyond the syntax of their
starting language, they must master the concepts of algorithms, data
structures, and the idioms used to accomplish common tasks. Most of the books
in my library concentrate on grammar, syntax, and standard libraries, while
glossing over good practices and common mistakes.
Perl has its own unique set of gotchas and strengths. Some make it easy for
beginners to hang themselves, and others could reduce the amount of code and
heartache needed. (Perl is fairly unique among languages in that it often lets
beginners and dabblers succeed despite their lack of formal training.)
Without further ado, here are Common Mistakes of Beginning Programmers (part
one).
Variable Variable Names
The mistake:
Beginners will often do something like this:
foreach ($i = 1; $i < 10; $i++) {
${"record$i"} = $i * $i;
}
Why it's a mistake:
Symbolic references are a
well documented pitfall. Besides that, Perl has built-in and easy-to-use
aggregate data types. That means that it makes a distinction between a thing
and a pile of things. In addition, you will need to keep track of the index
variable $i to know how many records you have.
Why they do it:
Beginning programs are often unaware of genericity and aggregation. They like
naming variables, and don't realize yet that you don't have to name everything
that's ever created.
The solution:
Use an array or hash (the aggregate data type) to hold the records. Not only
will Perl keep track of the number of records, it's easier to do common
operations on them.
for (1 .. 10) {
push @records, $_ * $_;
}
foreach my $record (@records) {
print $record, "\n";
}
Repetition without Abstraction
The mistake:
my $var1 = $query->param('var1');
my $var2 = $query->param('var2');
my $var3 = $query->param('var3');
my $var4 = $query->param('var4');
my $var5 = $query->param('var5');
my $var6 = $query->param('var6');
my $var7 = $query->param('var7');
my $var8 = $query->param('var8');
my $var9 = $query->param('var9');
my $var10 = $query->param('var10');
Yikes. At least he used CGI.pm, anyway. Here's another example:
$report = generate_report($foo);
open(FILE, ">>report.txt") or die "blah!";
print FILE "Report number: $i";
$i++;
#
# three lines to format header nicely
#
@report_lines = split(/\n/, $report);
print FILE $report_lines[0];
print FILE $report_lines[1];
print FILE $report_lines[2];
print FILE $report_lines[3];
print FILE $report_lines[4];
close FILE or die "blergh!";
# skip a few
$report = generate_report($bar);
open(FILE, ">>report.txt") or die "blah!";
print FILE "Report number: $i";
$i++;
#
# format the header again
#
@report_lines = split(/\n/, $report);
print FILE $report_lines[0];
# you see where this is going
Why it's a mistake:
Computers are supposed to make our lives easier. Anonymous data structures,
objects, loops, modules, macros, and templates are supposed to save effort.
Why do people not get beyond cutting and pasting?
Problems arise, as they always do, when a throwaway program becomes important
enough to keep around. Those programs have a way of attracting deadlines --
you'll have to add something, but you won't have time to do it right. Repeat
that another way. There's no better time to do a program right than before
anyone's depending on it.
Why they do it:
Designing things that have to work just once is easy. Designing things that
have to work a few different ways is difficult. Designing things that are
flexible, powerful, and easily understood is even worse. A few extra minutes of
typing seems like a small price to pay for not having to think too hard under a
time crunch.
The solution:
If you find yourself duplicating functionality in different places, stop.
Factor out the common elements and turn the variables into variables.
Sometimes this means you've been trying the wrong approach. Other times,
you're not approaching the problem the right way.
A literal translation of the first, somewhat better:
my %vars;
for (1 .. 10) {
$vars{"var$_"} = $query->param("var$_");
}
A whole lot better:
# change the form to use multiple selections with the same name
my @vars = $query->param('var');
# valid if you have a combobox or checkbox group
The second is lots nicer:
{
my $num_displayed = 0;
sub display_report {
my $data = shift;
my $report = generate_report($data);
open(FILE, ">>report.txt") or die "Can't append to report.txt: $!"
+;
print FILE "Report number: $num_displayed";
$num_displayed++;
print FILE $report;
}
} # end of enclosing scope for $num_displayed
Some items lend themselves to functions more than others. As you practice, you
will improve at figuring out which things are important and which are variable.
Fear of Documentation
The mistake:
Not typing 'perldoc perltoc'.
Why it's a mistake:
The Camel has a list price of US $49.95. Getting answers from
comp.lang.perl.misc, PerlMonks, and #Perl cost time and sometimes dignity. If
you have access to a computer with Perl on it, you have access to the
documentation -- the source material from which much of the Camel springs. (If
you don't have the documentation, you have a more serious problem called "BoFH
infestation". You'll have to fumigate.)
Why they do it:
Some people don't know the documentation is there. A careful nudge "Hey, it's
under the ActiveState program group or available by typing perldoc perltoc and
browsing for a while" is all that's needed. Others don't have the confidence
in their own abilities or the laziness necessary to motivate themselves into
being able to answer their own questions.
The solution:
Read the FAQ (
perldoc perlfaq). Read perldoc
perldoc. Learn how to search for
builtin function docs (perldoc -f function). Learn how to search the FAQ by
keyword (perldoc -q keyword). If you come across a word you don't know, see
perldoc perltoc. Yes, it takes a while. So does learning to be a basketball
player, a Bolivian cat herder, or an astroman. But the documentation is always
there, even when we're not. When you don't have time to wait for a response
from Usenet or the web, and when you're not in the mood to placate the IRC Ops,
you'll be glad you know how to search your own hard drive for the answers.
Update: Fixed an unintentional typo in the first beginner code, thanks to turnstep. chipmunk is right... I'm open to writing a second-parter, so send me your suggestions. Fixed a second unintentional typo in the second example, thanks to erix.
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
|
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.