HTML CSS PHP PERL

1.7 Warnings

 
Previous Table of Contents Next

1.7 Warnings

The question often arises of whether to leave warnings enabled in production code. Those against doing so say that you don't want the customer seeing "dirty laundry" generated by your programwhat if something quite innocuous in your program today turns out to be the subject of a warning added to a later version of Perl?

I prefer to leave the warnings in production programs. My point of view is that warnings are like strictness exceptions, only pickier, and should be treated the same: Either code to avoid the warning, or explicitly disable the warning around code where:

  • You know why the warning is being generated; and

  • You know that the warning is unlikely to be generated for any other reason; and

  • It's clearer to disable the warning than to recode.

If a new warning is added to Perl, the odds are that you'd want to know if you had code that triggered it. Today's warnings could become tomorrow's fatal error if you're using a feature that is being deprecated.

Don't scratch the itch to turn warnings off merely because they are inconvenient. Think of them instead as a programming mentor nagging you to make your code robust. You might respond, "No, I know what I'm doing, so don't complain about this again," by disabling the warning; or you might change the code.

For instance, suppose you are writing code that looks up people in a database by their username and inserts their e-mail address in a message template:


if (my $user = $db->lookup_user(username => $username))

{

  my $email = $user->email;

  open MAIL, "|$SENDMAIL" or croak "Mail: $!";

  print MAIL <<"EOMAIL";

To: archive\@listserver,$email

Subject: Your account

[...]

EOMAIL

  close MAIL;

}

Testing may go just fine. But suppose one day a user comes along who doesn't have a registered e-mail address, and so the email() accessor method returns undef. Without warnings, there will be no clue that the user didn't get the message they deserved unless someone inspects the e-mail archive that was copied.

I am not saying that the best way to write that e-mail-sending code is to allow the warning facility to catch the case where the address is undefined. It would have been better to have written something like:


if (my $user = $db->lookup_user(username => $username))

{

  if (my $email = $user->email)

  {

    open MAIL, "|$SENDMAIL" or croak "Mail: $!";

    print MAIL <<"EOMAIL";

To: archive\@listserver,$email

Subject: Your account

[...]

EOMAIL

    close MAIL;

  }

  else

  {

    # Handle the user not having an email address

  }

}

But you don't always have that much foresight. Leaving warnings enabled helps make up for that shortcoming.

I'll go into warnings and strictness in great detail in Chapter 5.

1.7.1 What Were They Doing?

Find out especially what the developer was optimizing their code for. Before you discard a complicated section in favor of something much simpler, find out whether it was written that way to meet performance requirements. Then find out whether it's still necessary to use those optimizations to meet the current requirements.

Code could have been optimized for several different factors, some of which I illustrate here with sample code, each example doing exactly the same thing (as explained by the comment in the first one).

  • Maintainability:

    
    # Print words with an even number of letters, AND even
    
    # number of each vowel, AND even position in the input
    
    OUTER: while (<>)
    
    {
    
      next if $. % 2;
    
      chomp;
    
      next if length() % 2;
    
      for my $vowel (qw/a e i o u y/)
    
      {
    
        my @vowels = /$vowel/g;
    
        next OUTER if @vowels % 2;
    
      }
    
      print "$_\n";
    
    }
    
    
  • Performance:

    
    while (<>)
    
    {
    
      next if ($. | (length() - 1)) % 2;
    
      next if tr/a// % 2;
    
      next if tr/e// % 2;
    
      next if tr/i// % 2;
    
      next if tr/o// % 2;
    
      next if tr/u// % 2;
    
      next if tr/y// % 2;
    
      print;
    
    }
    
    
  • Brevity:

    
    #!/usr/bin/perl -ln
    
    ($x=aeiouy)=~s#.#y/$&//|#g;eval("$x$.|y///c")%2&&next;print
    
    
  • Job security:

    
    @i = map { chomp; $x++ %2 ? $_ : () } <>;
    
    while ($i = shift @i)
    
    {
    
      ord(pack "w/a*", $i) & 1 and next;
    
      $_ = "$i\n";
    
      $i =~ s/$_(.*)$_/$1/ for qw/a e i o u y/;
    
      print unless $i =~ /[aeiouy]/;
    
    }
    
    

As you can see, the Perl philosophy of "There's More Than One Way To Do It" (TMTOWTDI) can result in radically different code, depending on whether the author wants it to be readable, fast, as short as possible, or incomprehensible, respectively.

Remember that it is the norm for programs to grow by evolution and accretion. The more successful the program was, the more likely it is to have had other functionality grafted onto it in response to requirements creep. Don't spend a long time trying to figure out the design rationale of a program; there may not be one left.

    Previous Table of Contents Next
    © 2000- NIV