Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Calling Perl Sub routine from variables 2

Status
Not open for further replies.

bdw238

MIS
Dec 15, 2005
52
0
0
GB

Can I call a perl function from variable like in php?

e.g in php


function addition ($a,$b)
echo ($a +$b), "\n";
}

$result = "addition";
$result(3,6);

Thanks


Brian
 
you wouldn't call perl sub routines in that manner, you would structure them differently like so...
Code:
sub addition {

# do sum using vars from @_
my $result = $_[0] + $_[1];

# return result
$result;     

}
you would then call the sub like so...
Code:
# Call function passing in vars
my $result = &addition(3,6);

# print result to screen
print $result;


"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you.
 
What you're trying to do involves the use of "soft references". Regulars to this forum will tell you that I'm very much against their use for a number of reasons. This page mostly discusses variables rather than subroutines but many of the problems are an issue for subs too. Additionally, depending on where the value of your $result variable comes from, you could be opening your program up to a whole new raft of security problems, if there's scope for users to effectively call any subroutine they want.

I'd do this by means of using a hash as a "dispatch table". Suppose you have subroutines called "addition", "subtraction", "multiplication" and "division", then you can do this:
Code:
my %operations = (
   addition => \&addition,
   subtractions => \&subtraction,
   multiplication => \& multiplication,
   division => \&division
);

my $action = 'addition'; # change this as necessary

if ( $operations{ $action } ) {
   $operations{ $action }->( 3, 6 );
}
else {
   print STDERR "Invalid operation\n";
}

Admittedly, it is a little more unwieldy to write, but it's waaaaaaaaaay more secure and easy to debug.

 
ishnid why would you do that rather than make a routine as I showed?

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you.
 
Ishnid Thanks that's what am looking for.

What I trying to do is create a method of dynamically calling 4 different types of file transfer(rcp, sftp,ftp binary,ftp ascii) sub routined depending on field within CSV file without using if ... then elsif ... then, etc.

Psudo Code (This is very highlevel).

Loop until TERM Signal.

User Publishs a file to directory.
Perl Program notices new file in directory.
Useing the userid of the file as key, read CSV file to
obtain transfer type and other parms.
Call transfer sub routine depending on file type.
etc..
End loop

The addition function was just an example.


Brian
 
@1DMF - I think you've misunderstood the question. He's trying to dynamically call a subroutine based on the value of $result.

Code:
$result = "addition";
$result(3,6);
What he meant by this was that he wanted to call the "addition" subroutine, passing in 3 and 6 as parameters. That's how I understood the question anyway.
 
if variable $foo contains a function name e.g. 'additio' you can call the function by the name reference as
&$foo, look at this
Code:
# function
sub addition{
  my ($a, $b) = @_;
  return ($a+$b);
}

$a = 1; $b = 2;
# normal call
print "\$a=$a, \$b=$b, \&addition($a,$b)=", &addition($a,$b), "\n";

# reference to the function by name
$foo='addition';
print "\$a=$a, \$b=$b, \$foo=$foo, \&\$foo($a,$b)=", &$foo($a,$b), "\n";
 
I understand now what they are trying to do, my question is why would you do that rather than as they say using nested if,then,else and calling relevant routine.

is there any benefit? would it run quicker? at least an if,then,else is easier to understand and debug.


but what I have noticed is the way you created a hash and the value of each key was a reference " \ ".

so like hashes, scalars, arrays etc... you can also make a scalar a reference to the space in memory that a sub resides.

also this bit
Code:
$operations{ $action }->( 3, 6 );
looks very OOP , you seem to be referencing a hash keys value, which is actually a reference to a sub passing in the @_ vars using -> .

having a sub held in a scalar as a reference and then doing the following...

my $sub = $operations{ $action }; does this always run the sub and not pass you the reference to the sub.

would you have to do $sub = \$operation{ $action }; to maintain the reference to the sub within $sub




"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you.
 
Think of it as a function pointer. Whether you consider this to be easier to debug than nested if-then-else sequences is a matter of choice. I'd prefer it.

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::perlDesignPatterns)[/small]
 
appreciate it, just want to understand it a bit more

and does $retval = $operation{ $action }; return the sub output to retval?

or do you need to use $retval = $operation{ $action }->(); ie do you need to use -> to fire the sub, or only use -> if there are @_ vars to passs to the sub?

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you.
 
$bar=$foo($a,$b);
don't work, but
$bar=&$foo($a,$b);
works.
 
@mikron , are you sure? I tried it and all I get is
Software error:
Can't use string ("addition") as a subroutine ref while "strict refs" in use at \cgi-bin\admin\test.cgi line 43.

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you.
 
1DMF,

when I try it, it works fine, this code
Code:
# function
sub addition{
  my ($a, $b) = @_;
  return ($a+$b);
}

$a = 1; $b = 2;
my $foo='addition';
my $bar=&$foo($a,$b);
print "\$bar=$bar\n";
delivers the result $bar = 3

But your problem could be that you have in your code
Code:
use strict;
This delivers by me an error
Can't use string ("addition") as a subroutine ref while "strict refs" in use at..
 
Couple of things to sort out here:

mikrom: that's the "soft references" approach I mentioned earlier. There are numerous problems with this kind of approach (not least that it causes your entire program to die if the subroutine specified doesn't exist). The dispatch-table method takes a little more effort, but the results are more than worth it. The fact that "strict" complains about it should tell you something in itself.

@1DMF - Firstly, you really *have* learned a lot on this forum. A star to you for not considering for one moment the solution of just disabling strict checking!

As for this:
Code:
$retval = $operation{ $action };
This takes the subroutine reference that's in the $operation hash and puts that reference into $retval. The sub doesn't get run with this code. Two ways to run the subroutine:
Code:
$sub_ref->();
&$sub_ref;

# you'll need curly brackets if it's in a hash:
&{ $hash{sub_ref} };
 
thanks ishnid, most of what I know I owe to you, so the credit and the star is all yours!!!

you answered what I was trying to understand would the sub be run without ->() and no it wouldn't so ->() is not just the mechanism for passing the @_ vars but also the method!

again thanks for your time and effort in explaining things to me :)



"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top