Why would I use Perl anonymous subroutines instead of a named one?

user102881 picture user102881 · May 7, 2009 · Viewed 14k times · Source

I'm just curious why one would choose to use an anonymous subroutine, versus a named one, in Perl. Thanks.

Answer

innaM picture innaM · May 7, 2009
  • You can store anonymous subs in arrays, hashes and scalars.
  • You can build them at runtime
  • You can pass them as arguments to other functions.
  • You get to keep variables in the surrounding scope.

The last point is probably the most important, because it's often the most unexpected facet of named vs. anonymous subroutines in Perl. Example:

sub outer
{
  my $a = 123;

  sub inner
  {
    print $a, "\n";
  }

  # At this point, $a is 123, so this call should always print 123, right?
  inner();

  $a = 456;
}

outer(); # prints 123
outer(); # prints 456! Surprise!

But change "inner" from a named subroutine to a reference to an anonymous subroutine and it works is a much less surprising manner:

sub outer
{
  my $a = 123;

  my $inner = sub
  {
    print $a, "\n";
  };

  # At this point, $a is 123, and since the anonymous subrotine 
  # whose reference is stored in $inner closes over $a in the 
  # "expected" way...
  $inner->();

  $a = 456;
}

# ...we see the "expected" results
outer(); # prints 123
outer(); # prints 123

(Of course, everyone's expectations are different, thus the "scare quotes" around "expected.")

Here's an example use in real code (though it should be noted that the File::Find interface is generally considered to be a poor one—due to its use of global variables, not its use of anonymous subroutines):

sub find_files
{
  my @files;

  my $wanted = sub
  { 
    if($something)
    {
      push @files, $File::Find::name;
    }
  };

  # The find() function called here is imported from File::Find
  find({ wanted => $wanted }, $directory);

  return @files;
}

Passing a named subroutine as the value of the wanted parameter would require polluting the namespace with a routine that may only be used once, and defining a named subroutine within the find_files() subroutine would exhibit the "unexpected" behavior demonstrated earlier.