jh- has asked for the wisdom of the Perl Monks concerning the following question:

O Mighty Monks,
Sorry for the probably confusing title, I just don't know how to suppress the question to a short(er) form.. ;)

Basically I need to call a subroutine when I have its name on a variable. Like this:

use strict; use warnings; sub test { print "something"; } sub another_test { print "something else"; } sub third_test { print "another unimaginative statement"; } my @ary = qw( test another_test third_test ); my $sub_i_want_to_call = $ary[rand(@ary)];

And now I'd want to call the subroutine which name is on $sub_i_want_to_call. How would I do this?

Thanks in advance,
Joeli

Replies are listed 'Best First'.
Re: How to call sub defined in a variable?
by moritz (Cardinal) on Jan 25, 2009 at 21:23 UTC
    Initialize the array differently (ie with references to subs):
    my @subs = (\&test, \&another_test, \&third_test); my $sub_i_want_to_call = $subs[rand(@subs)]; $sub_i_want_to_call->();

    See perlreftut for more informations.

    Update: fixed copy&paste error in the code, thanks to ww++ for noticing.

      Or using the distributive nature of referencing:
      my @ary = \( &test, &another_test, &third_test ); my $sub_i_want_to_call = $ary[rand(@ary)]; $sub_i_want_to_call->();

        Thanks for suggestions, but I'm afraid that initializing the array with references instead of string literals would require lots of work in the context I'd need it.

        I actually stumbled upon this, but it relies on no strict 'refs', and I'm left wondering if there's a way to do something similiar with use strict?

        my @ary = qw( test another_test third_test ); my $sub_i_want_to_call = $ary[rand(@ary)]; { no strict 'refs'; &{$sub_i_want_to_call}; }
Re: How to call sub defined in a variable?
by kyle (Abbot) on Jan 25, 2009 at 22:16 UTC

    You might also find some useful ideas in calling subroutines from variables. For instance,

    my $sub_i_want_to_call = $ary[rand @ary]; my $sub_ref = __PACKAGE__->can( $sub_i_want_to_call ); $sub_ref->();

    Or, without the variables,

    __PACKAGE__->can( $ary[rand @ary] )->();
Re: How to call sub defined in a variable?
by GrandFather (Saint) on Jan 25, 2009 at 21:44 UTC

    In the context of OO code you could:

    use strict; use warnings; my $self = bless {tests => [qw(something else another bogus)]}; for my $testName (@{$self->{tests}}) { my $test = $self->can ("test_$testName"); if (! $test) { warn "Test $testName not available\n"; next; } print "Running test $testName:\n"; $test->($self); } print "Testing complete\n"; sub test_something { print "something\n"; } sub test_else { print "something else\n"; } sub test_another { print "another unimaginative statement\n"; }

    Prints:

    Running test something: Test bogus not available something Running test else: something else Running test another: another unimaginative statement Testing complete

    which allows derived classes to add tests that are managed by the parent class.


    Perl's payment curve coincides with its learning curve.

      Usually the lack of distinction between function and method is a problem in Perl, but here it means that you can use can() on a package name even if it's not a class and get back a subroutine reference even if it's not a method.

      package My::Awesome::Package; use 5.010; sub foo { ... } sub bar { ... } sub baz { ... } package main; for my $func (qw( foo bar baz quux )) { next unless my $func_ref = My::Awesome::Package->can( $func ); say "Found code for '$func': ", $func->(); }
Re: How to call sub defined in a variable?
by revdiablo (Prior) on Jan 25, 2009 at 22:46 UTC

    Another way to do it. Put your code references in a hash, otherwise known as a dispatch table:

    # Pick a more descriptive name for this hash, depending on your need my %subroutines = ( test => \&test, another_test => \&another_test, third_test => \&third_test, ); for (qw(test another_test third_test)) { $subroutines{$_}->(); }

    This lets you define exactly which routines you can call using this method, rather than opening up everything and anything in the main namespace.

Re: How to call sub defined in a variable?
by snoopy (Curate) on Jan 26, 2009 at 01:29 UTC
    Also consider putting the subroutines in their own name-space:
    #!/usr/bin/perl use strict; use warnings; package MySubs; sub test { print "something"; } sub another_test { print "something else"; } sub third_test { print "another unimaginative statement"; } 1; package main; my @ary = qw( test another_test third_test ); my $sub_i_want_to_call = $ary[rand(@ary)]; my $subref = MySubs->can($sub_i_want_to_call); &$subref() if $subref;
Re: How to call sub defined in a variable?
by dasaftei (Initiate) on Jan 27, 2009 at 03:22 UTC
    You can use eval($sub_i_want_to_call); Good luck!