Tuesday, April 5, 2011

How do I iterate over/dereference an array of subroutine refs in Perl?

I’m trying to figure out how to iterate over an array of subroutine refs.

What’s wrong with this syntax?

use strict;
use warnings;

sub yell { print "Ahh!\n"; }
sub kick { print "Boot!\n"; }
sub scream { print "Eeek!\n"; }

my @routines = (\&yell, \&kick, \&scream);
foreach my $routine_ref (@routines) {
  my &routine = &{$routine_ref};
  &routine;
}

Thanks in advance!

From stackoverflow
  • Try this:

    use strict;
    use warnings;
    
    sub yell { print "Ahh!\n"; }
    sub kick { print "Boot!\n"; }
    sub scream { print "Eeek!\n"; }
    
    my @routines = (\&yell, \&kick, \&scream);
    foreach my $routine_ref (@routines) {
      &$routine_ref ();
    }
    
    Axeman : &$routine_ref calls it. The parens do nothing.
  • foreach my $routine_ref (@routines) {
            $routine_ref->();
    }
    
  • In your foreach loop, the following is a syntax error:

    my &routine;
    

    Your variable $routine_ref already has a reference to the subroutine, so all you need to do at that point is call it:

    for my $routine_ref (@routines) {
        &{$routine_ref};
    }
    

    As always with Perl, "There's More Than One Way to Do It." For example, if any of those subroutines took parameters, you could pass them inside parenthesis like this:

    for my $routine_ref (@routines) {
      $routine_ref->();
    }
    

    Also note that I've used for instead of foreach, which is a best pratice put forth by Damian Conway in Perl Best Practices.

    Kent Fredric : I've always preferred the latter example, its less-ambiguous in behaviour to me. ( +1 )
    brian d foy : You probably don't want to dereference it with just the &. Without the parens, that uses the current value of @_ as the implicit argument list, and that's usually never what you mean to do.
    j_random_hacker : Good point Brian.

0 comments:

Post a Comment