Perl: How to check what is being returned from a subroutine - perl

I have a subroutine that will return two hashes when all goes well. But the sub checkouts output of command and if it matches a certain pattern, it returns with "-1". Is there anyway to check the return of the subroutine from where I called it?
Kinda like:
if (RETURN_VALUE == -1){
do something}
else
go as normal with the hashes

How could one function return two hashes?
If you mean hashrefs, the check would be quite simple:
my ($h1,$h2) = myFunction();
if ( !ref($h1) || (ref($h1) ne "HASH"))
{
die 'error';
}

You function should return references to the two hashes on success and nothing upon failure. Then you can just check the truth value of the function call.
sub myfunc {
my %hash1;
my %hash2;
return (\%hash1, \%hash2);
}
my $ref1;
my $ref2;
unless (($ref1, $ref2) = myfunc()) {
print "Something went wrong\n";
} else {
print "OK\n";
}

If you return two (or any number for that matter) hashes from a subroutine, the result will be a single hash. You will not be able to separate the original hashes from the result in a normal manner. Returning hash references will not exhibit this problem.
Suppose foo() returns two hash references when the pattern is matched and returns -1 when it does not match.
my ( $value_1, $value_2 ) = foo;
if ( $value_1 == -1 ) {
# pattern did not match
}
else { # for strict checks: elsif ( ref $value_1 eq 'HASH' && ref $value_2 eq 'HASH' ) {
# pattern matched
}

Related

Perl optimization: inlining a function changed the results

I profiled some code, and there is one function which stood out and I was wondering if there is a way to optimize it:
The function is defined as:
sub convert_arrayref {
if(ref($_[0]) eq 'ARRAY') {
return join(($_[1] || ","), #{$_[0]});
}
else {
return $_[0];
}
}
Most of the times the else block will get executed, and I was wondering if I could inline it rather than making a function call. The calling code looks as follows:
$data = convert_arrayref($data, '&')
So, what I did was change the calling code as:
if ($data eq 'ARRAY') {
$data = join('&', $data)
}
I thought this would be equivalent. However, the results are different. I am wondering if I have done something wrong here.
You get different results because you did not replicate the functionality of the if clause. You need to use ref to check if your variable is an array reference, and you need to deference the variable:
if (ref($data) eq 'ARRAY') {
$data = join('&', #{ $data })
}

Replace a variable as string with results from a subroutine in perl

I am trying to replace the variable "ex" with it's string value(which it gets from subroutine "potatoex()" and put it in the definition of another variable "goodge",
not getting any syntax error but this seems to be not working out.
Please help.
sub potatoex {
my $potato="Junos: 17.4DCB";
if($potato = ~/"Junos: 17.4[a-zA-Z0-9_.]*"/) {
print "/var/home/smoketest/dhcpv6.pl.28709.log";
}
}
main :
{
my $ex= potatoex();
my $goodge= "Apurva $ex Arnav";
print $goodge;
}
CURRENT O/P : /var/home/smoketest/dhcpv6.pl.28709.logApurva 1 Arnav
EXPECTED O/P: Apurva /var/home/smoketest/dhcpv6.pl.28709.log Arnav
Thanks,
Apurva
You are printing from your subroutine instead of returning the value from it. Try using return in potatoex.
sub potatoex {
my $potato = q{Junos: 17.4DCB};
my $returnVal = '';
if( $potato =~ /Junos: 17\.4[a-zA-Z0-9_.]*/ ) {
$returnVal = q{/var/home/smoketest/dhcpv6.pl.28709.log};
}
$returnVal;
}
{
my $ex = potatoex();
my $goodge = qq{Apurva $ex Arnav};
print $goodge;
}
While you could use return in an if block above (instead of print), I instead decided to use a variable, which will always return either the value you are trying to or an empty string. You could explicitly state the return return returnVal;, but it isn't required as perl allows implicit returns (make note of this and figure out if it should fit in your best practices or not).

Access an array item in Perl after generating that array

Hello I want to access an specific array item based in a condition previously checked. I leave the code here:
elsif (scalar(#{$boss->bosses}) > 1) {
foreach my $pa (#{$boss->bosses}) {
my $p = My::Model::Group->new(id => $pa->group_id);
push(#$groups, $p);
$valid_pass = 1 if ($pa->checkPassword($self->param('password')));
}
if ($valid_pass) {
my $pa_id = $pa->id;
my $pa_partner_id = $pa->group_id;
}
else {
}
}
What I want to do is, if that if in the array that comes, I check if the password is correct, so if it's correct, then I want to take the id and the group_id of the array item to use it in a function to be able to log them in.
Your for loop is doing two things at once: producing a list of My::Model::Group objects in #$groups, and finding the first boss whose password checks out.
I suggest that you split them up into two clear operations, and the List::Util modules first operator is ideal for the second task
Here's how it would look. I've extracted the result of the method call $boss->bosses into a variable $bosses to avoid repeated calls to the method
Note that you don't need to apply scalar to an array when checking its size. The > and all the other comparators impose scalar context anyway
I've taken much of my code from your question, and I'm a little concerned that you extract values for $pa_id and $pa_partner_id and then just discard them. But I imagine that you know what you really want to do here
use List::Util 'first';
my $bosses = $boss->bosses;
if ( ... ) {
...;
}
elsif ( #$bosses > 1 ) {
#$groups = map { My::Model::Group->new( id => $_->group_id ) } #$bosses;
my $password = $self->param( 'password' );
my $pa = first { $_->checkPassword( $password ) } #$bosses;
if ( $pa ) {
my $pa_id = $pa->id;
my $pa_partner_id = $pa->group_id;
}
else {
...;
}
}

perl cyclic reference. Is this what is happening

I am trying to write a daemon with perl. Now this daemon has the following code
sub b {
my $data;
if (some condition) {
$data->{"endsmeet"} = 1;
} else {
$data->{"endsmeet"} = 2;
}
my $newData = a($data);
}
sub a {
my ($data) = #_;
my %a = ();
my $newData = {
endsmeet => undef,
};
$a{"boo"} = $data->{"endsmeet"};
$newData->{"endsmeet"} = \%a;
return $newData;
}
My question is from the above, does the reference for %a go away and does it get cleaned up when b goes out of scope?
b returns the value of $newdata, which is a reference to an anon hash, which holds a reference to %a, which holds a scalar in the element with key boo.
If the value returned by b not stored, nothing will be referencing the value of $newdata, so it will get freed, so nothing will be referencing the anon hash, so it will get freed, so nothing will reference the scalar in the element with key boo, so it will get freed.
No cycles. No leak.

How can I return a whole hash map in Perl?

I have a hash called
%values
Now I want to return the whole hash in a subroutine
sub getvalues {
return $values;
}
But then I got an error, because $value needs a definition and my program stops. If I'm using
sub getvalues {
return %values;
}
it seems to work, but my program is very slow and don't get further... So how can I return the whole map?
It would be nice to return the hash reference instead of hash,what you need to do is
First stote the hash into the hash ref then return it like
sub getvalues {
my %values = (test => "SO");
my $values = \%values;
return $values;
}