Don't strive for elegant, clever code. Try to develop a good coding style by writing code that is concise, yet easy to understand. It's much easier to find bugs in concise, simple code, and such code tends to have fewer bugs.

The "one week ago" example from the previous section is not concise. There is a lot of redundancy in it, and as a result it is harder to debug than it needs to be. Here is a condensed version of the main loop:

for (0..6) {
    next if --$day;
    $year--, $month=12 unless --$month;
    $day = $month != 2
        ? $month_len[$month-1] 
        : ($year % 400 =  = 0 or ($year % 4 =  = 0 and $year % 100))
            ? 29
            : 28;
}

This version may seem quite difficult to understand and even harder to maintain, but for those who are used to reading idiomatic Perl, part of this code is easier to understand.

Larry Wall, the author of Perl, is a linguist. He tried to define the syntax of Perl in a way that makes working in Perl much like working in English. So it's a good idea to learn Perl's coding idioms—some of them might seem odd at first, but once you get used to them, you will find it difficult to understand how you could have lived without them. We'll present just a few of the more common Perl coding idioms here.

You should try to write code that is readable and avoids redundancy. For example, it's better to write:

unless ($i) {...}

than:

if ($i =  = 0) {...}

if you want to just test for truth.

Use a concise, Perlish style:

for my $j (0..6) {...}

instead of the syntax used in some other languages:

for (my $j=0; $j<=6; $j++) {...}

It's much simpler to write and comprehend code like this:

print "something" if $debug;

than this:

if ($debug) {
    print "something";
}

A good style that improves understanding and readability and reduces the chances of having a bug is shown below, in the form of yet another rewrite of our "one week ago" code:

for (0..6) {
    $day--;
    next if $day;

    $month--;
    unless ($month){
        $year--;
        $month=12
    }

    if($month =  = 2){ # February
        $day = ($year % 400 =  = 0 or ($year % 4 =  = 0 and $year % 100)) 
             ? 29 : 28;
    } else {
        $day = $month_len[$month-1];
    }
}

This is a happy medium between the excessively verbose style of the first version and the very obscure second version.

After debugging this obscure code for a while, we came up with a much simpler two-liner, which is much faster and easier to understand:

sub date_a_week_ago {
    my($day, $month, $year) = (localtime(time-7*24*60*60))[3..5];
    return sprintf "%02d/%02d/%04d", $month+1, $day, $year+1900;
}

Just take the current date in seconds since epoch as time( ) returns, subtract a week in seconds (7661 × 24 × 60 × 60),[52] and feed the result to localtime( ). Voilà—we have the date of one week ago!

[52]Perl folds the constants at compile time.

Why is the last version important, when the first one works just fine? Not because of performance issues (although this last one is twice as fast as the first), but because there are more chances to have a bug in the first version than there are in the last one.

Of course, instead of inventing the date_a_week_ago( ) function and spending all this time debugging it, we could have just used a standard module from CPAN to provide the same functionality (with zero debugging time). In this case, Date::Calc comes to the rescue,[53] and we will write the code as:

[53]See also Class::Date and Date::Manip.

use Date::Calc;
sub date_a_week_ago {
    my($year,$month,$day) = 
        Date::Calc::Add_Delta_Days(Date::Calc::Today, -7);
    return sprintf "%02d/%02d/%04d", $month, $day, $year;
}

We simply use Date::Calc::Today( ), which returns a list of three values—year, month, and day—which are immediately fed into the function Date::Calc::Add_Delta_Days( ). This allows us to get the date N days from now in either direction. We use -7 to ask for a date from one week ago. Since we are relying on this standard CPAN module, there is not much to debug here; the function has no complicated logic where one can expect bugs. In contrast, our original implementation was really difficult to understand, and it was very easy to make mistakes.

We will use this example once again to stress that it's better to use standard modules than to reinvent them.