Beefy Boxes and Bandwidth Generously Provided by pair Networks Frank
Don't ask to ask, just ask

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??
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, 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.

In reply to Common Beginner Mistakes by chromatic

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • 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
  • Outside of code tags, you may need to use entities for some characters:
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others cooling their heels in the Monastery: (8)
    As of 2014-04-16 06:18 GMT
    Find Nodes?
      Voting Booth?

      April first is:

      Results (415 votes), past polls