Perl best practice: prefer foreach to for

Perl problem: When you don’t use Perl every day, it’s hard to remember the combination of the for loop syntax and how to deal with the special $_ variable to refer to each element within the body of the loop.

Solution: As I write this today, I still can’t remember how to get this for loop and $_ syntax to work, at least not without pulling out a book, or looking it up on the internet. A much better solution is to just use Perl’s foreach syntax, and never look back.

Discussion

I just spent a few minutes trying to get the following Perl for loop to work, and got frustrated at wasting my time. As a warning, this code still does not work:

@files = qw(/foo/bar/file.pdf /foo/baz/file2.jpg);

# ERROR: I can't remember how to work with $_ in the following for loop
for (@files)
{
  # exclude any files in the /foo/bar hierarchy
  # this doesn't work because $_ is not getting assigned the way i expected ... argh ...
  next if /bar/;

  # print all other files
  print "$file\n";
}

The foreach loop fix

Fortunately just at that time my brain kicked in and said, “Quit screwing around with the for loop syntax, and just use the foreach syntax.” Fortunately I took my brain’s advice, and fixed the code like this, using the foreach syntax:

@files = qw(/foo/bar/file.pdf /foo/baz/file2.jpg);

foreach $file (@files)
{
  # exclude any files in the /foo/bar hierarchy
  next if $file =~ /bar/;

  # print all other files
  print "$file\n";
}

Note that in this example I don’t have to deal with the $_ variable. I just assign $file to each element in the @files array, and then refer to $file from within the body of the foreach loop.

Summary

As of today, I have no plans to ever use the Perl for operate ever again, certainly not in a situation like this. I can't remember the “special” syntax, unless I use Perl all the time, which I don’t any more. And the foreach loop syntax is much more readable.

Comments

Permalink

AFAICT, the only problem with your first ("for") loop is this:

  print "$file\n";

which should be

  print "$_\n";

instead. $_ was indeed getting set the way you expected it to, you were just printing the wrong thing.

$ cat perltest 
#!/usr/bin/perl
@files = qw(/foo/bar/file.pdf /foo/baz/file2.jpg);
for (@files)
{
  next if /bar/;
  print "$_\n";
}
$ ./perltest 
/foo/baz/file2.jpg

Add new comment

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.