2

Is it possible to get the example below to work so that the name of the subroutine is stored and called via a scalar variable?

use strict;
use warnings;

sub doit {
    my ($who) = @_;
    print "Make us some coffee $who!\n";
}

sub sayit {
    my ($what) = @_;
    print "$what\n";
}

my $action = 'doit';
$action('john');
TLP
  • 66,756
  • 10
  • 92
  • 149
gatorreina
  • 864
  • 5
  • 14
  • Does this answer your question? [How can I elegantly call a Perl subroutine whose name is held in a variable?](https://stackoverflow.com/questions/1915616/how-can-i-elegantly-call-a-perl-subroutine-whose-name-is-held-in-a-variable) – Chad Mar 01 '22 at 00:42

2 Answers2

6

You could put it in a hash:

my %hash;
$hash{'doit'} = \&doit;
$hash{'doit'}->('Mike');

Or you could make it an anonymous sub right away

my %hash = ( doit  => sub {  ... },
             sayit => sub { .... },
            ....);

As Dada mentions, it is a scalar value, so it can also be put in a scalar variable:

my $command = \&doit;
$command->('Mike');

Technically you can also put a string into a scalar, and use that as a subroutine:

my $action = 'doit';
$action->('Mike');      # breaks strict 'refs'

But if you are using use strict, like you should, it will not allow you, and will die with the error:

Can't use string ("doit") as a subroutine ref while "strict refs" in use...

So don't do that. If you want to use strings to refer to subs, using a hash is the proper way. But if you still want to, you can

no strict 'refs';

To get away with it.

TLP
  • 66,756
  • 10
  • 92
  • 149
  • Or, `my $action = \&doit` (depends on the context, which we don't have). – Dada Feb 27 '22 at 14:50
  • @Dada I suppose you could do `my $doit = \&doit`, but there would not be much difference from just `doit()`. I assumed the goal was to access different subs via different strings, a lookup table. – TLP Feb 27 '22 at 15:16
  • Or, there might be a condition to set `action` (eg, `my $action = ... ? \&doit : \&sayit`, or `if (...) { ... $action = \&doit } else { ... $action = \&sayit }`). Or, `doit` might be passed to a function (eg, `sub f { my $ action = shift; ... } ... f(\&doit)`). – Dada Feb 27 '22 at 15:26
  • 1
    All right, you convinced me, I will add it. – TLP Feb 27 '22 at 15:35
0

According to an answer to this question: How can I elegantly call a Perl subroutine whose name is held in a variable?

You could try this:

__PACKAGE__->can($action)->('john');
Chad
  • 693
  • 5
  • 17