in reply to calling a function as a value from a hash

While shmem has demostrated the calling styles, I'd like to add some notes. Nevertheless, you'll find more on perlreftut or perlref.

So basically, as f00li5h said, you're building a dispatch table. You use a key/index based on user input to obtain the correspondent code (subroutine) and dispatch it.

The first style,

$op_map{$op_choice}->(@args);
As you probably know, the selected subroutine is in $op_map{$op_choise}, a code reference. A common way to dereference a reference is by using the arrow operator. The parentheses are there for passing in parameters and required in this case, whether or not you actually have parameters to pass in. That's the basic way to call functions (allthough you can omit the parentheses in some cases). So if you had no parameters, you would call it $op_map{$op_choice}->();

The second style,

&{$op_map{$op_choice}}(@args);
Another approach in dereferencing is by surrounding the references in {} and prepending it with a sigli (a character that signifies a thing), hence the &{}. As you may recall, the & is (optionally) used to call a subroutine. The parentheses are there, again, for passing in parameters and required if you do have parameters to pass in. Otherwise, &{$op_map{$op_choice}}; will do (but see WARNING below).

As for myself, I'd rather like to firstly check the input if it indeed exists in the table. This way, if the input is not one of the keys, I have options whether to simply throw an exception or use some default instead.

die "Unknown choice: $op_choice\n" unless my $cmd = $op_map{$op_choice};
Or, if I set a default choice,
my $default = 'OP1'; my $cmd = $op_map{$op_choice} || $op_map{$default};
And later,
$cmd->();
Or,
&$cmd; # see WARNING below
I see the first style is more elegant, and the first is shorter. I personally prefer the second one.

WARNING: One has to be careful of the &$cmd. This form has special meaning in that it passes in the parameters for the current subroutines (@_) to the subroutine reference in $cmd. So, &$cmd is basically the same as &$cmd(@_). If this is what you want then go ahead. If you're in doubt however, use parentheses, whether or not you have parameters. In fact, this is the recommended practice, whether or not it's explicitly called inside a subroutine. Oh well, you may never know when your whole script is actually wrapped in a generated subroutine (thinking mod_perl for example).


Updated: added the WARNING. Thanks ikegami :-)

Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

Replies are listed 'Best First'.
Re^2: calling a function as a value from a hash
by ikegami (Patriarch) on Apr 15, 2007 at 16:35 UTC

    &$cmd; is not the same as &$cmd();. With &$cmd;, you'll get the parent's @_, which means @_ could have values even though no arguments were provided. It also means you risk clobbering the parent's @_. I advise against &$cmd;.

Re^2: calling a function as a value from a hash
by Beechbone (Friar) on Apr 16, 2007 at 15:39 UTC
    Three more ways for a fallback action:
    ($op_map{$op_choice}||$defaultaction)->(@args); ($op_map{$op_choice}||$op_map{defaultaction})->(@args); ($op_map{$op_choice}||sub {die "'$op_choice' is invalid"})->(@args);

    Search, Ask, Know