Why I can't do "shift subroutine_name()" in Perl? - perl

Why does this code return an Not an ARRAY reference error?
sub Prog {
my $var1 = 1;
my $var2 = 2;
($var1, $var2);
}
my $variable = shift &Prog;
print "$variable\n";
If I use an intermediate array, I avoid the error:
my #intermediate_array = &Prog;
my $variable = shift #intermediate_array;
print "$variable\n";
The above code now outputs "1".

The subroutine Prog returns a list of scalars. The shift function only operates on an array. Arrays and lists are not the same thing. Arrays have storage, but lists do not.
If what you want is to get the first element of the list that Prog returns, do this:
sub Prog {
return ( 'this', 'that' );
}
my $var = (Prog())[0];
print "$var\n";
I changed the sub invocation to Prog() instead of &Prog because the latter is decidedly old style.
You can also assign the first element to a scalar like others are showing:
my ($var) = Prog();
This is roughly the same as:
my ($var, $ignored_var) = Prog();
and then ignoring $ignored_var. If you want to make it clear that you're ignoring the second value without actually giving it a variable, you can do this:
my ($var, undef) = Prog();

Prog is returning a list, not an array. Operations like shift modify the array and cannot be used on lists.
You can instead do:
my ($variable) = Prog; # $variable is now 1:
# Prog is evaluated in list context
# and the results assigned to the list ($variable)
Note that you don't need the &.

Related

what is the best way to assign a value inside a nested hash?

My code constructs a hash %oprAtnNOW that contains a hash ref, where both the keys and values inside
$oprAtnNOW{opt} are determined at run time.
The sample code below demonstrates that a single command suffices to extract a value from the anonymous hash referenced by $oprAtnNOW{opt}.
But assigning a value doesn't work like that.
When I try to assign the string wolf to the key Dog, something very strange happens.
When I use Dumper to look at the result, it appears that the value assigned was 'wolf, with a single quote pasted to the start of the string;
and when I use print to look at it, it looks like SCALAR(something).
(The end of my code demonstrates that 'wolf does not print out as SCALAR(something), so Dumper has something else in mind.)
So my sample code contains a workaround:
deference the anonymous inner hash; assign key and value in the now named, temporary hash; clobber the previous $oprAtnNOW{opt}
with a reference to the temporary, named hash.
Why does the direct method yield such a strange result?
What is the true content of this SCALAR thing?
Is there a way to do this with a single command, without my multi-step workaround?
#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper qw(Dumper);
$Data::Dumper::Sortkeys = 1;
my %oprAtnNOW;
${$oprAtnNOW{opt}{Dog}} = 'wolf';
print Dumper {%oprAtnNOW};
print join('', '$oprAtnNOW{opt}{Dog}==', $oprAtnNOW{opt}{Dog}, "\n",);
{
my %tmp_oprAtnNOW_opt = %{$oprAtnNOW{opt}} if(defined $oprAtnNOW{opt});
$tmp_oprAtnNOW_opt{Dog} = 'wolf'; # will clobber any previous value for Dog
$oprAtnNOW{opt} = {%tmp_oprAtnNOW_opt};
}
print Dumper {%oprAtnNOW};
print join('', '$oprAtnNOW{opt}{Dog}==', $oprAtnNOW{opt}{Dog}, "\n",);
my $teststring = join('', "\x27", 'wolf',);
print "teststring==$teststring\n";
You want
$oprAtnNOW{opt}{Dog} = 'wolf';
$BLOCK = EXPR; expects BLOCK to return a reference to a scalar.
Thanks to autovivification, one is created for you if needed. In other words,
${$oprAtnNOW{opt}{Dog}} = 'wolf';
is short for
${ $oprAtnNOW{opt}{Dog} //= \my $anon } = 'wolf';
which could also be written as
my $anon = 'wolf';
$oprAtnNOW{opt}{Dog} = \$anon;
This is not what you want. You don't want to assign a reference to the hash; you want to assign the string wolf. To achieve that, you can use
$oprAtnNOW{opt}{Dog} = 'wolf';
This short for
$oprAtnNOW{opt}->{Dog} = 'wolf';
aka
${ $oprAtnNOW{opt} }{Dog} = 'wolf';
The latter is of the form
$BLOCK{Dog} = 'wolf';
which, like $NAME{Dog}, is an assignment to a hash element.

Perl find out if X is an element in an array

I don't know why small things are too not working for me in Perl. I am sorry for that.
I have been trying it around 2 hrs but i couldn't get the results.
my $technologies = 'json.jquery..,php.linux.';
my #techarray = split(',',$technologies);
#my #techarray = [
# 'json.jquery..',
# 'php.linux.'
# ];
my $search_id = 'json.jquery..';
check_val(#techarray, $search_id);
And i am doing a "if" to search the above item in array. but it is not working for me.
sub check_val{
my #techarray = shift;
my $search_id = shift;
if (grep {$_ eq $search_id} #techarray) {
print "It is there \n";
}else{
print "It is not there \n";
}
}
Output: It always going to else condition and returns "It is not there!" :(
Any idea. Am i done with any stupid mistakes?
You are using an anonymous array [ ... ] there, which as a scalar (reference) is then assigned to #techarray, as its only element. It is like #arr = 'a';. An array is defined by ( ... ).
A remedy is to either define an array, my #techarray = ( ... ), or to properly define an arrayref and then dereference when you search
my $rtecharray = [ .... ];
if (grep {$_ eq $search_id} #$rtecharray) {
# ....
}
For all kinds of list manipulations have a look at List::Util and List::MoreUtils.
Updated to changes in the question, as the sub was added
This has something else, which is more instructive.
As you pass an array to a function it is passed as a flat list of its elements. Then in the function the first shift picks up the first element,
and then the second shift picks up the second one.
Then the search is over the array with only 'json.jquery..' element, for 'php.linux.' string.
Instead, you can pass a reference,
check_val(\#techarray, $search_id);
and use it as such in the function.
Note that if you pass the array and get arguments in the function as
my (#array, $search_id) = #_; # WRONG
you are in fact getting all of #_ into #array.
See, for example, this post (passing to function) and this post (returning from function).
In general I'd recommend passing lists by reference.

Where does a Perl subroutine get values missing from the actual parameters?

I came across the following Perl subroutine get_billable_pages while chasing a bug. It takes 12 arguments.
sub get_billable_pages {
my ($dbc,
$bill_pages, $page_count, $cover_page_count,
$domain_det_page, $bill_cover_page, $virtual_page_billing,
$job, $bsj, $xqn,
$direction, $attempt,
) = #_;
my $billable_pages = 0;
if ($virtual_page_billing) {
my #row;
### Below is testing on the existence of the 11th and 12th parameters ###
if ( length($direction) && length($attempt) ) {
$dbc->xdb_execute("
SELECT convert(int, value)
FROM job_attribute_detail_atmp_tbl
WHERE job = $job
AND billing_sub_job = $bsj
AND xqn = $xqn
AND direction = '$direction'
AND attempt = $attempt
AND attribute = 1
");
}
else {
$dbc->xdb_execute("
SELECT convert(int, value)
FROM job_attribute_detail_tbl
WHERE job = $job
AND billing_sub_job = $bsj
AND xqn = $xqn
AND attribute = 1
");
}
$cnt = 0;
...;
But is sometimes called with only 10 arguments
$tmp_det = get_billable_pages(
$dbc2,
$row[6], $row[8], $row[7],
$domain_det_page, $bill_cover_page, $virtual_page_billing,
$job1, $bsj1, $row[3],
);
The function does a check on the 11th and 12th arguments.
What are the 11th and 12th arguments when the function is passed only 10 arguments?
Is it a bug to call the function with only 10 arguments because the 11th and 12th arguments end up being random values?
I am thinking this may be the source of the bug because the 12th argument had a funky value when the program failed.
I did not see another definition of the function which takes only 10 arguments.
The values are copied out of the parameter array #_ to the list of scalar variables.
If the array is shorter than the list, then the excess variables are set to undef. If the array is longer than the list, then excess array elements are ignored.
Note that the original array #_ is unmodified by the assignment. No values are created or lost, so it remains the definitive source of the actual parameters passed when the subroutine is called.
ikegami suggested that I should provide some Perl code to demonstrate the assignment of arrays to lists of scalars. Here is that Perl code, based mostly on his edit
use strict;
use warnings;
use Data::Dumper;
my $x = 44; # Make sure that we
my $y = 55; # know if they change
my #params = (8); # Make a dummy parameter array with only one value
($x, $y) = #params; # Copy as if this is were a subroutine
print Dumper $x, $y; # Let's see our parameters
print Dumper \#params; # And how the parameter array looks
output
$VAR1 = 8;
$VAR2 = undef;
$VAR1 = [ 8 ];
So both $x and $y are modified, but if there are insufficient values in the array then undef is used instead. It is as if the source array was extended indefinitely with undef elements.
Now let's look at the logic of the Perl code. undef evaluates as false for the purposes of conditional tests, but you apply the length operator like this
if ( length($direction) && length($attempt) ) { ... }
If you have use warnings in place as you should, Perl would normally produce a Use of uninitialized value warning. However length is unusual in that, if you ask for the length of an undef value (and you are running version 12 or later of Perl 5) it will just return undef instead of warning you.
Regarding "I did not see another definition of the function which takes only 10 arguments", Perl doesn't have function templates like C++ and Java - it is up to the code in the subroutine to look at what it has been passed and behave accordingly.
No, it's not a bug. The remaining arguments are "undef" and you can check for this situation
sub foo {
my ($x, $y) = #_;
print " x is undef\n" unless defined $x;
print " y is undef\n" unless defined $y;
}
foo(1);
prints
y is undef

Dereferencing in case of $_[0], $_[1] ..... so on

please see the below code:
$scalar = 10;
subroutine(\$scalar);
sub subroutine {
my $subroutine_scalar = ${$_[0]}; #note you need the {} brackets, or this doesn't work!
print "$subroutine_scalar\n";
}
In the code above you can see the comment written "note you need the {} brackets, or this doesn't work!" . Please explain the reason that why we cant use the same statement as:
my $subroutine_scalar = $$_[0];
i.e. without using the curly brackets.
Many people have already given correct answers here. I wanted to add an example I found illuminating. You can read the documentation in perldoc perlref for more information.
Your problem is one of ambiguity, you have two operations $$ and [0] working on the same identifier _, and the result depends on which operation is performed first. We can make it less ambiguous by using the support curly braces ${ ... }. $$_[0] could (for a human anyway) possibly mean:
${$$_}[0] -- dereference the scalar $_, then take its first element.
${$_[0]} -- take element 0 of the array #_ and dereference it.
As you can see, these two cases refer to completely different variables, #_ and $_.
Of course, for Perl it is not ambiguous, we simply get the first option, since dereferencing is performed before key lookup. We need the support curly braces to override this dereferencing, and that is why your example does not "work" without support braces.
You might consider a slightly less confusing functionality for your subroutine. Instead of trying to do two things at once (get the argument and dereference it), you can do it in two stages:
sub foo {
my $n = shift;
print $$n;
}
Here, we take the first argument off #_ with shift, and then dereference it. Clean and simple.
Most often, you will not be using references to scalar variables, however. And in those cases, you can make use of the arrow operator ->
my #array = (1,2,3);
foo(\#array);
sub foo {
my $aref = shift;
print $aref->[0];
}
I find using the arrow operator to be preferable to the $$ syntax.
${ $x }[0] grabs the value of element 0 in the array referenced by $x.
${ $x[0] } grabs the value of scalar referenced by the element 0 of the array #x.
>perl -E"$x=['def']; #x=\'abc'; say ${ $x }[0];"
def
>perl -E"$x=['def']; #x=\'abc'; say ${ $x[0] };"
abc
$$x[0] is short for ${ $x }[0].
>perl -E"$x=['def']; #x=\'abc'; say $$x[0];"
def
my $subroutine_scalar = $$_[0];
is same as
my $subroutine_scalar = $_->[0]; # $_ is array reference
On the other hand,
my $subroutine_scalar = ${$_[0]};
dereferences scalar ref for first element of #_ array, and can be written as
my ($sref) = #_;
my $subroutine_scalar = ${$sref}; # or $$sref for short
Because $$_[0] means ${$_}[0].
Consider these two pieces of code which both print 10:
sub subroutine1 {
my $scalar = 10;
my $ref_scalar = \$scalar;
my #array = ($ref_scalar);
my $subroutine_scalar = ${$array[0]};
print "$subroutine_scalar\n";
}
sub subroutine2 {
my #array = (10);
my $ref_array = \#array;
my $subroutine_scalar = $$ref_array[0];
print "$subroutine_scalar\n";
}
In subroutine1, #array is an array containing the reference of $scalar. So the first step is to get the first element by $array[0], and then deference it.
While in subroutine2, #array is an array containing an scalar 10, and $ref_array is its reference. So the first step is to get the array by $ref_array, and then index the array.

perl: why \(1,2) is SCALAR? How to dereference it?

Here's the code:
$ref = \(1,2);
print "$ref\n";
print "#$ref\n";
It gives me:
SCALAR(0xa15a68)
Not an ARRAY reference at ./test.pl line 23.
I was trying to write a wrapper function that calls a function with unknown result type.
It should call the real function, save the result, do some other stuff and return the saved result. But it turned out that for the caller that expects a scalar value, returning an array and returning a list in parentheses are different things. This is why I tried to use references.
What you want is this:
$ref = [ 1, 2 ];
In your code:
$ref = \(1,2);
What the right hand side does is create a list of references, instead of a reference to an array. It's the same as this:
$ref = ( \1, \2 );
Since you're assigning that list to a scalar, all but the last item is thrown away, and $ref is set to a reference to the scalar value 2, which is probably not what you want.
See perldoc perlref.
Note that this behavior is consistent for non-literal values as well, such as subroutine calls. If you call a sub like this:
$val = function();
then the function sub is called in scalar context, and can choose to return a different value than if it were called in list context. (See perldoc -f wantarray.) If it chooses to return a list anyway, all but the last element of the list will be discarded, and that last element will be assigned to $val:
sub fun1() { return 1; }
sub fun2() { return (1,2); }
my $f1 = fun1();
my $f2 = fun2();
# $f1 is 1, and $f2 is 2
my $r1 = \( fun1() );
my $r2 = \( fun2() );
# $r1 is a ref to 1, and $r2 is a ref to 2
The unary reference operator \ returns the references of its RHS argument. If that argument is a list, then a list of references is returned.
If a list is used in scalar context, the last element of that list is returned:
1, 2 # list of 1, 2
\(1, 2) # list of \1, \2
$ref = \(1, 2) # list is used in scalar context
$ref = \2 # equivalent
Lists and Arrays are distinct: Lists are a syntactic construct, while an array is a data structure.