Ways to call a function in Perl - perl

Can I call a subroutine by taking its name dynamically as below?
printf "Enter subroutine name: ";
$var1 = <STDIN>; # Input is E111;
$var1();
Function E111:
sub E111(){
printf "Hi, this is E111 & Bye \n";
}
Is there a possibility to do it like this?

There are very few hard limits on what you can do in Perl, but this is one of those places that you don't want to go to. One normal way about it is to use a dispatch table
my %call = (
'name_1' => sub { function body }, # inline, anonymous subroutine
'name_2' => \&func, # or take a reference to a sub
...
);
where sub {} is an anonymous subroutine, so the value for name_1 is a code reference.
Then you use it as
my $name = <STDIN>;
chomp $name;
$call{$name}->(#arguments); # runs the code associated with $name
This finds the key $name in the hash and dereferences its value, the coderef; so it runs that code.
Documentation: overview perlintro, tutorial perlreftut, and references perlref and perlsub.

A solution:
print "Enter subroutine name:";
$var1 = <STDIN>;
chomp($var1);
eval "$var1()";
sub E111 {
print "Hi this is E111 & Bye \n";
}

Related

Perl: return an array from subroutine

Perl noob.
I am having trouble understanding returning an array value from a subroutine in a module.
The script has the following:
print "Enter your first and last name.\n";
chomp(my $fullname = <STDIN>); #input is 'testing this' all lower case
Jhusbands::Loginpass->check_name($fullname);
print "$fullname\n";
The module includes the following subroutine:
sub check_name {
my $class = shift;
if ($_[0] =~ /^\w+\s+\w+$/ ) {
#_ = split( / /, $_[0]);
foreach $_ (#_) {
$_ = ucfirst lc for #_;
#_ = join(" ", #_);
print Dumper(#_) . "\n";
return #_;
}
}
}
I am taking the name, checking it for only first and last (I'll get to else statements later), splitting it, correcting the case, and joining again. Dumper displays the final array as:
$VAR1 = 'Testing This';
So it appears to be working that far. However, the return vale for $fullname in the script displays the all lower case:
testing this
Why is it not taking the corrected uppercase variable that Dumper displays as the last array iteration?
You don't assign the return to anything. Also, the sub manipulates #_ which it shouldn't be doing, as discussed below. It can also be greatly simplified
sub check_name {
my ($class, $name) = #_;
if ($name =~ /^\w+\s+\w+$/) {
return join ' ', map { ucfirst lc } split ' ', $name;
}
return; # returns "undef" (as input wasn't in expected format)
}
Then the caller can do
my $fullname = Jhusbands::Loginpass->check_name($name);
print "$fullname\n" if $fullname;
A sub's return should always be checked but in this case even more so, since it processes its input conditionally. I renamed the input to sub (to $name), for clarity.
If the code in the sub is meant to change the $fullname by writing directly to #_ (and you had no return for that reason), that fails since after the specific manipulations $_[0] isn't any more aliased to the argument that was passed.
In any case, doing that is very tricky, can lead to opaque code -- and is unneeded. To directly change the argument pass it as a reference and write to it. However, it is probably far clearer and less error prone to return the result in this case.
It should be noted that the above name "processing" runs into the standard problems with processing of names, due to their bewildering variety. If this needs to be comprehensive then the name parsing should be dispatched to a rounded library (or procedure) that can deal with the possible dirersity.
Thanks to ikegami for comments bringing this up with examples, as well as a more direct way:
$name =~ s/(\w+)/\u\L$1/g;
return $name;
which with /r introduced in v5.14 can be written as
return $name =~ s/(\w+)/\u\L$1/gr;
If $name has no word-characters (\w) and there is no match this returns the same string.

How to pass entire subroutine into hashtable data using perl?

I have the following subroutine which i should pass the routine as hashtable and that hashtable should be again called inside another subroutine using perl?
input file(from linux command bdata):
NAME PEND RUN SUSP JLIM JLIMR RATE HAPPY
achandra 0 48 0 2000 50:2000 151217 100%
agutta 1 5 0 100 50:100 16561 83%
My subroutine:
sub g_usrs_data()
{
my($lines) = #_;
my $header_found = 0;
my #headers = ();
my $row_count = 0;
my %table_data = ();
my %row_data = ();
$lines=`bdata`;
#print $lines;
foreach (split("\n",$lines)) {
if (/NAME\s*PEND/) {
$header_found = 1;
#headers =split;
}
elsif (/^\s*$/)
{
$header_found=0;
}
$row_data{$row_count++} = $_;
#print $_;
}
My query:
How can i pass my subroutine as hash into another subroutine?
example:
g_usrs_data() -> this is my subroutine .
the above subroutine should be passed into another subroutine (i.e into usrs_hash as hash table)
example:
create_db(usrs_hash,$sql1m)
Subroutines can be passed around as code references. See perlreftut and perlsub.
An example with an anonymous subroutine
use warnings;
use strict;
my $rc = sub {
my #args = #_;
print "\tIn coderef. Got: |#_|\n";
return 7;
}; # note the semicolon!
sub use_rc {
my ($coderef, #other_args) = #_;
my $ret = $coderef->('arguments', 'to', 'pass');
return $ret;
}
my $res = use_rc($rc);
print "$res\n";
This silly program prints
In coderef. Got: |arguments to pass|
7
Notes on code references
The anonymous subroutine is assigned to a scalar $rc, making that a code reference
With an existing (named) sub, say func, a code reference is made by my $rc = \&func;
This $rc is a normal scalar variable, that can be passed to subroutines like any other
The sub is then called by $rc->(); where in parenthesis we can pass it arguments
Note that the syntax for creating and using them are just like for other data types
As anonymous assign by = sub { }, much like = [ ] (arrayref) and = { } (hashref)
For a named sub use & instead of a sigil, so \& for sub vs. \# (array) and \% (hash)
They are used by ->(), much like ->[] (arrayref) and ->{} (hashref)
For references in general see perlreftut. Subroutines are covered in depth in perlsub.
See for example this post on anonymous subs, with a number of answers.
For far more see this article from Mastering Perl and this article from The Effective Perler.

Perl: Modify variable passed as param to subroutine

I need to modify a variable inside a routine, so it keeps the changes after leaving the routine. Here's an example:
$text = "hello";
&convert_to_uppercase($text);
print $text;
I want to see "HELLO" on the screen, not "hello".
The routine would be:
sub convert_to_uppercase($text){
<something like $text = uc($text);>
}
I know how to do it in PHP, but it seems that the parameters are not changed the same way. And, I've been searching everywhere and I couldn't find a concrete answer.
You really shouldn't use an ampersand & when calling a Perl subroutine. It is necessary only when treating the code as a data item, for instance when taking a reference, like \&convert_to_uppercase. Using it in a call hasn't been necessary since version 4 of Perl 5, and it does some arcane things that you probably don't want.
It is unusual for subroutines to modify their parameters, but the elements of #_ are aliases of the actual parameters so you can do what you ask by modifying that array.
If you write your subroutine like this
sub convert_to_uppercase {
$_[0] = uc $_[0];
}
then it will do what you ask. But it is generally best to return the modified value so that the decision on whether to overwrite the original value can be taken by the calling code. For instance, if I have
sub upper_case {
uc shift;
}
then it can be called either as
my $text = "hello";
$text = upper_case($text);
print $text;
which does as you require, and modifies $text; or as
my $text = "hello";
print upper_case($text);
which leaves $text unchanged, but returns the altered value.
Passing a reference and modifying the original variable inside the subroutine would be done like this:
$text = 'hello';
convert_to_uppercase(\$text); #notice the \ before $text
print $text;
sub convert_to_uppercase { #perl doesn't specify arguments here
### arguments will be in #_, so #_ is now a list like ('hello')
my $ref = shift; #$ref is NOT 'hello'. it's '$text'
### add some output so you can see what's going on:
print 'Variable $ref is: ', $ref, " \n"; #will print some hex number like SCALAR(0xad1d2)
print 'Variable ${$ref} is: ', ${$ref}, " \n"; #will print 'hello'
# Now do what this function is supposed to do:
${$ref} = uc ${$ref}; #it's modifying the original variable, not a copy of it
}
The other way is to create a return value inside the subroutine and modify the variable outside of the subroutine:
$text = 'hello';
$text = convert_to_uppercase($text); #there's no \ this time
print $text;
sub convert_to_uppercase {
# #_ contains 'hello'
my $input = shift; #$input is 'hello'
return uc $input; #returns 'HELLO'
}
But the convert_to_uppercase routine seems redundant because that's what uc does. Skip all of that and just do this:
$text = 'hello';
$text = uc $text;

perl subroutine argument lists - "pass by alias"?

I just looked in disbelief at this sequence:
my $line;
$rc = getline($line); # read next line and store in $line
I had understood all along that Perl arguments were passed by value, so whenever I've needed to pass in a large structure, or pass in a variable to be updated, I've passed a ref.
Reading the fine print in perldoc, however, I've learned that #_ is composed of aliases to the variables mentioned in the argument list. After reading the next bit of data, getline() returns it with $_[0] = $data;, which stores $data directly into $line.
I do like this - it's like passing by reference in C++. However, I haven't found a way to assign a more meaningful name to $_[0]. Is there any?
You can, its not very pretty:
use strict;
use warnings;
sub inc {
# manipulate the local symbol table
# to refer to the alias by $name
our $name; local *name = \$_[0];
# $name is an alias to first argument
$name++;
}
my $x = 1;
inc($x);
print $x; # 2
The easiest way is probably just to use a loop, since loops alias their arguments to a name; i.e.
sub my_sub {
for my $arg ( $_[0] ) {
code here sees $arg as an alias for $_[0]
}
}
A version of #Steve's code that allows for multiple distinct arguments:
sub my_sub {
SUB:
for my $thisarg ( $_[0] ) {
for my $thatarg ($_[1]) {
code here sees $thisarg and $thatarg as aliases
last SUB;
}
}
}
Of course this brings multilevel nestings and its own code readability issues, so use it only when absolutely neccessary.

How to run an anonymous function in Perl?

(sub {
print 1;
})();
sub {
print 1;
}();
I tried various ways, all are wrong...
(sub { ... }) will give you the pointer to the function so you must call by reference.
(sub { print "Hello world\n" })->();
The other easy method, as pointed out by Blagovest Buyukliev would be to dereference the function pointer and call that using the { } operators
&{ sub { print "Hello World" }}();
Yay, I didn't expect you folks to come up with that much possibilities. But you're right, this is perl and TIMTOWTDI: +1 for creativitiy!
But to be honest, I use hardly another form than the following:
The Basic Syntax
my $greet = sub {
my ( $name ) = #_;
print "Hello $name\n";
};
# ...
$greet->( 'asker' )
It's pretty straight forward: sub {} returns a reference to a sub routine, which you can store and pass around like any other scalar. You can than call it by dereferencing. There is also a second syntax to dereference: &{ $sub }( 'asker' ), but I personally prefer the arrow syntax, because I find it more readable and it pretty much aligns with dereferencing hashes $hash->{ $key } and arrays $array->[ $index ]. More information on references can be found in perldoc perlref.
I think the other given examples are a bit advanced, but why not have a look at them:
Goto
sub bar {goto $foo};
bar;
Rarely seen and much feared these days. But at least it's a goto &function, which is considered less harmful than it's crooked friends: goto LABEL or goto EXPRESSION ( they are deprecated since 5.12 and raise a warning ). There are actually some circumstances, when you want to use that form, because this is not a usual function call. The calling function ( bar in the given example ) will not appear in the callling stack. And you don't pass your parameters, but the current #_ will be used. Have a look at this:
use Carp qw( cluck );
my $cluck = sub {
my ( $message ) = #_;
cluck $message . "\n";
};
sub invisible {
#_ = ( 'fake' );
goto $cluck;
}
invisible( 'real' );
Output:
fake at bar.pl line 5
main::__ANON__('fake') called at bar.pl line 14
And there is no hint of an invisible function in the stack trace. More info on goto in perldoc -f goto.
Method Calls
''->$foo;
# or
undef->$foo;
If you call a method on an object, the first parameter passed to that method will be the invocant ( usually an instance or the class name ). Did i already say that TIMTOWTCallAFunction?
# this is just a normal named sub
sub ask {
my ( $name, $question ) = #_;
print "$question, $name?\n";
};
my $ask = \&ask; # lets take a reference to that sub
my $question = "What's up";
'asker'->ask( $question ); # 1: doesn't work
my $meth_name = 'ask';
'asker'->$meth_name( $question ); # 2: doesn't work either
'asker'->$ask( $question ); # 1: this works
In the snippet above are two calls, which won't work, because perl will try to find a method called ask in package asker ( actually it would work if that code was in the said package ). But the third one succeeds, because you already give perl the right method and it doesn't need to search for it. As always: more info in the perldoc I can't find any reason right now, to excuse this in production code.
Conclusion
Originally I didn't intend to write that much, but I think it's important to have the common solution at the beginning of an answer and some explanations to the unusual constructs. I admit to be kind of selfish here: Every one of us could end up maintaining someones code, who found this question and just copied the topmost example.
There is not much need in Perl to call an anonymous subroutine where it is defined. In general you can achieve any type of scoping you need with bare blocks. The one use case that comes to mind is to create an aliased array:
my $alias = sub {\#_}->(my ($x, $y, $z));
$x = $z = 0;
$y = 1;
print "#$alias"; # '0 1 0'
Otherwise, you would usually store an anonymous subroutine in a variable or data structure. The following calling styles work with both a variable and a sub {...} declaration:
dereference arrow: sub {...}->(args) or $code->(args)
dereference sigil: &{sub {...}}(args) or &$code(args)
if you have the coderef in a scalar, you can also use it as a method on regular and blessed values.
my $method = sub {...};
$obj->$method # same as $method->($obj)
$obj->$method(...) # $method->($obj, ...)
[1, 2, 3]->$method # $method->([1, 2, 3])
[1, 2, 3]->$method(...) # $method->([1, 2, 3], ...)
I'm endlessly amused by finding ways to call anonymous functions:
$foo = sub {say 1};
sub bar {goto $foo};
bar;
''->$foo; # technically a method, along with the lovely:
undef->$foo;
() = sort $foo 1,1; # if you have only two arguments
and, of course, the obvious:
&$foo();
$foo->();
You need arrow operator:
(sub { print 1;})->();
You might not even need an anonymous function if you want to run a block of code and there is zero or one input. You can use map instead.
Just for the side effect:
map { print 1 } 1;
Transform data, take care to assign to a list:
my ($data) = map { $_ * $_ } 2;
# ------------------------------------------------------
# perl: filter array using given function
# ------------------------------------------------------
sub filter {
my ($arr1, $func) = #_;
my #arr2=();
foreach ( #{$arr1} ) {
push ( #arr2, $_ ) if $func->( $_ );
};
return #arr2;
}
# ------------------------------------------------------
# get files from dir
# ------------------------------------------------------
sub getFiles{
my ($p) = #_;
opendir my $dir, $p or die "Cannot open directory: $!";
my #files=readdir $dir;
closedir $dir;
#return files and directories that not ignored but not links
return filter \#files, (sub { my $f = $p.(shift);return ((-f $f) || (-d $f)) && (! -l $f) } );
}