You can call the function like so:
$op_map{$op_choice}->(@args);
or, as well
&{$op_map{$op_choice}}(@args);
I prefer the first form.
--shmem
_($_=" "x(1<<5)."?\n".q·/)Oo. G°\ /
/\_¯/(q /
---------------------------- \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
| [reply] [d/l] [select] |
$op_map{$op_choice}->(@args);
or, as well
&{$op_map{$op_choice}}(@args);
Or even $op_map{$op_choice}(@args)
| [reply] [d/l] [select] |
| [reply] [d/l] |
Hi shobhit,
I'm with shmem, in that $op_map{$op_choice}->(@args); is the form that feels the most natural. Such a technique is commonly called a "dispatch table".
But it's worth noting that a good to habit to get into is to put a comma at the end of each line, including the last. So you're safer if you put a comma after \&op2, as in:
my %op_map=( 'OP1' => \&op1,
'OP2' => \&op2,
);
That's because later, when you add a function or functions at the end, you won't get an error due to a missing comma.
s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
| [reply] [d/l] [select] |
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!
| [reply] [d/l] [select] |
&$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;.
| [reply] [d/l] [select] |
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);
| [reply] [d/l] |
Since the discussion is becoming one of style preferenece, I'll add mine. Dispatch tables are often a suprise to someone reading through code. It's common for there to be only one in a module, if that, so it's good to call the reader's attention to what's going on.
While I might use
$op_map{$op_choice}->(@args);
for a one-off, or where I was using it a lot, for most code I'd do something along the lines of naikonta's later suggestion, only with some correspondence between the names, as in
my $op = $op_map{$op_choice};
$op->(@args);
This separates the lookup from the invocation, so the invocation is easier to see. It also makes adding a default function easier, as naikonta already showed. | [reply] [d/l] [select] |