Assign the value to variable in 2 different sub and call the variable based on the value in perl - perl

I need help in calling the value from the variable from 2 different subroutines and assigning the value based on input.
For example: I have 3 different subroutines named sub xxx, sub yyy and sub execute. Two subroutines named as xxx and yyy will be defined as the input of the value. The execute sub will take the input based on the value supplied while executing main.pl:
sub xxx
{
my $input = "repository_1";
}
sub yyy
{
my $input = "repository_2";
}
sub execute
{
$output=$input;
print "This is the Repository connected : $output";
}
When I run the main.pl script, it will call either sub xxx or sub yyy based on the input, and it will execute the output if repository_1 or repository_2.
For example, if I run $main.pl xxx, I am able to connect to sub xxx and skip sub yyy. But I want the sub execute to take the input from sub xxx as repository_1. And so that I can display the $output of the repository like this:
$ main.pl xxx
This is the Repository connected : repository_1

The issue with your code is the my $input lines create variables that are local to the xxx and yyy functions. That means $input will not have any value when you use it in the execute function.
Running your code with use strict and use warnings will show the problem
use strict;
use warnings;
sub xxx
{
my $input = "repository_1";
}
sub yyy
{
my $input = "repository_2";
}
sub execute
{
my $output = $input;
print "This is the Repository connected : $output\n";
}
outputs
Global symbol "$input" requires explicit package name (did you forget to declare "my $input"?) at try.pl line 16.
A very quick fix is to declare $input at a global scope and use #ARGV to trigger the calling of xxx or yyy.
use strict;
use warnings;
my $input;
sub xxx
{
$input = "repository_1";
}
sub yyy
{
$input = "repository_2";
}
sub execute
{
my $output = $input;
print "This is the Repository connected : $output\n";
}
xxx() if $ARGV[0] eq 'xxx';
yyy() if $ARGV[0] eq 'yyy';
execute();
$ perl main.pl xxx
This is the Repository connected : repository_1
NOTE: the use of #ARGV in the code above is purely to create a self-contained script that allows xxx or yyy to be executed on demand. The real code should not only this technique if the control of xxx and yyy needs to be controlled from the command line.
Recommend that all you Perl code includes the use strict and use warnings. It catches issues like this for for you for free.
Without knowing more about your script, it is difficult to make any other recommendations.

A typical use for a dispatch table†, so that we can call the right function based on input (or perhaps other key words but without having to hardcode it)
use warnings;
use strict;
use feature 'say';
my $input = shift // die "Need input\n";
sub xx
{
#say "In xx(), my input: #_";
# ... work out output:
my $output = "repository_1";
return $output;
}
sub yy
{
#say "In yy(), my input: #_";
# ...
my $output = "repository_2";
return $output;
}
sub execute
{
my #output = #_;
print "This is the Repository connected : #output\n";
}
my %dispatch = ( xx => \&xx, yy => \&yy );
# Is there a function to dispatch to for the given input?
my $call_sub = $dispatch{$input} // die "Input ($input) not supported";
execute( $call_sub->() );
Can add more sophisticated handling for unsupported input.
Prints
> perl dispatch_ex.pl yy
This is the Repository connected : repository_2
† In Perl this is normally implemented as a hash which has code references for values and their keys are suitable names that allow us to retrieve them as needed.
A code reference is either a reference to a named function, as used here, or it is an anonymous subroutine
my $code_reference = \&name_of_some_function;
# or
my $code_reference = sub { ... };
This is then a scalar like any other, that can be passed around, stored in arrays or hashes (as a value, as having it as a key -- even though technically allowed -- wouldn't make sense).
Note that it is the function name, no parenthesis. Then it is called (dereferenced) as
$code_reference->( #arguments );
If it is called without any arguments we still need (empty) parenthesis.
Documentation: a tutorial perlreftut and a reference perlref, and perlsub.

Related

Ways to call a function in 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";
}

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 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) } );
}

Can I dynamically get a list of functions or function names from any Perl module?

I would like to dynamically get a list of either function names (as strings) or function references from any arbitrary Perl module available on my system. This would include modules that may or may not have, e.g., a global #EXPORT_OK array in its namespace. Is such a feat possible? How does one pull it off if so?
Edit: From reading perlmod, I see that %Some::Module:: serves as a symbol table for Some::Module. Is this the correct place to be looking? If so, how can I whittle the table down to just the function names in Some::Module?
You're on the right track. To wittle down the full symbol table to just the subs, something like this can be done (Hat tip "Mastering Perl", ch 8, for main package version of this):
use strict; # need to turn off refs when needed
package X;
sub x {1;};
sub y {1;};
our $y = 1;
our $z = 2;
package main;
foreach my $entry ( keys %X:: ) {
no strict 'refs';
if (defined &{"X::$entry"}) {
print "sub $entry is defined\n" ;
}
}
# OUTPUT
sub y is defined
sub x is defined
You may find this simple script handy:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
# dump of object's symbol table:
foreach my $className (#ARGV)
{
print "symbols in $className:";
eval "require $className";
die "Can't load $className: $#" if $#;
no strict 'refs';
print Dumper(\%{"main::${className}::"});
}
But, if you're doing this in production code, I'd use Package::Stash instead:
my #subs_in_foo = Package::Stash->new('Foo')->list_all_symbols('CODE');
I'm using Perl 5.20. This works on my machine:
use strict;
package foo;
our $some_var;
sub func1 { return 'func1'}
sub func2 { return 'func2'}
package main;
sub callable {
my ($x) = #_;
return defined(&$x);
}
while (my ($k, $v) = each(%foo::)) {
if (callable($v)) {
print("$k\n");
}
}
# output:
# func1
# func2