perl reference and dereference on return statement - perl

I am learning perl, and have a problem related to references.
I am working on the function get_id.
If i return $self->{_id}, I will get two array address which cannot run (c).
In my understanding, $a is the reference and #{$a} is array and #{$a}[0] would return the value 0?
This is my first time post question on stackoverflow, therefore the explaination may not clear enough, sorry about that.
#a1 = [0]
#a2 = [1]
my self{
_id = [\#a1,\#a2]; } //given
sub get_id(){
my $self = shift;
return $self->{_id};
}
sub print{
...
my $a = $obj -> get_id();
my $b = #{$a}[0] * 100; // c (given)
..
}

When $arr is a reference to an array, #$arr or #{ $arr } is the array it refers to. The first (or zeroth) element of the array is $arr->[0] (or $$arr[0], but the arrow notation is more common).
The following
my #arr = [0];
creates an array with a single element, and that element is an array reference. To get the 0, you need to do
$arr[0]->[0]
which can be shortened to
$arr[0][0]
To create an array with 0 as the single element, use
my #arr = (0);
BTW, don't use $a and $b, they are special variables used in sort. Lexicalising them with my can lead to bugs that are hard to debug.

Related

Referenced array to array yield size instead of actual array

Probably a simple answer, but this has annoyed me for quite some time. I have a variable that looks to be a reference to an array of objects (hashes), i.e. the subroutine retrieving this array returns this
return \#my_entities;
All places I have looked states, in order to loop through these entities I need to do something like this
for my $obj (#{$ref}) {
#do stuff
}
Why is it then if I do as above: #{$ref}, I get SCALAR "2" if I have 2 elements instead of the array? It's like #{$ref} gives me the size rather than the array.
EDIT: To elaborate more, it appears the operators work opposite in my context, if I do
scalar $ref
I get the array. and if I do
#($ref)
I get the length. Is there some hidden option somewhere that reverses the behavior?
I have only recently started working with perl and the code base is rather huge so it would be impossible to paste it all in here, but the gist of the trouble spot looks very similar to one of the answers below. Basically a sub returns a reference to an array/list and that list is being attempted looped through.
If I do this
sub f {
my #my_entities = #_;
return \#my_entities;
}
my $ref = f(qw( a b c d ));
for my $obj (#{$ref}) {
print $obj;
}
I get 4 as a result, it doesn't loop through elements. If I change #{$ref} to scalar $ref I get the a b c d listed.
Should be said I am using the Camelcade debugger to run this on a linux server through Webstorm on my laptop.
If you evaluate #{$ref} in scalar context, you will get the number of elements in the array referenced by $ref (just as if you had evaluated #a in scalar context).
If you evaluate #{$ref} in list context, you will get the elements of the array referenced by $ref (just as if you had evaluated #a in list context).
In the code you posted, you are doing the latter.
use strict;
use warnings;
use feature qw( say );
sub f {
my #my_entities = #_;
return \#my_entities;
}
my $ref = f(qw( a b c d ));
for my $obj (#{$ref}) {
say $obj;
}
Output:
a
b
c
d
There is no difference here between array references and actual arrays. If you evaluate an array in list context, you get the array elements. If you evaluate an array in scalar context, you get the number of elements in the array.
my #array = qw[A B C];
print "#array"; # list context gives 'A B C'
print scalar #array; # scalar context gives 3
my $array_ref = \#array;
print "#$array_ref"; # list context gives 'A B C'
print scalar #$array_ref; # scalar context gives 3

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.

Why I can't do "shift subroutine_name()" in 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 &.

How to dereference hash references

UPDATE: Everything I know about referencing/dereferencing came from here: http://www.thegeekstuff.com/2010/06/perl-array-reference-examples/
I'm working with a library that (from the library documentation):
Returns a reference to an array of hash references
This conceptually makes sense to me (i'm not new to programming) but doesn't make sense functionally (i'm, apparently, very new to perl).
Here's some code:
my $Obj = QA::STK::ModuleImUsing->new(arguments, to, new);
$Obj->createClient();
$Obj->sync( ['/tmp/files/...']);
my $result = $Obj->method_in_question(['/tmp/files/ff-latest.xml']);
So far so good. $result now holds the reference to an array.
So when I do this:
print "Result: #{ $result} \n";
I get:
Result: HASH(0x20d95b0)
Lovely! But I still need to dereference the hash. However, here's where things get weird (or maybe they've already gotten weird?).
my $hash_ref = #{ $result};
print Dump($hash_ref));
I get this:
$VAR1 = 1;
Which...isn't what I was expecting at all.
Are my expectations wrong or am I dereferencing things in the wrong way?
If #$result is an array then your LHS must be a list. Otherwise $hashref will be assigned the array size.
my ($hash_ref) = #{ $result};
print Dump($hash_ref));
We have a %hash.
To this, we have a hash reference $hashref = \%hash
This hashref is inside an array #array = ($hashref)
We get an array reference: $arrayref = \#array
This is our result: $result = $arrayref. Not let's work backwards:
#result_array = #$result
$result_hashref = $result_array[0] or combined: $result_hashref = $result->[0]
%result_hash = %$result_hashref or combined: %result_hash = %{ $result->[0] } (note that these make a copy)
To get an element in the result hash, we can do
$result_hash{$key}
$result_hashref->{$key}
$result->[0]{$key}
Note that $scalar = #{ $arrayref } does not work as you expect, because an array (which #{ … } is) returns the length of the array in scalar context. To force list context in an assignment, put the left hand side into parens: (…) = here_is_list_context (where … is a list of zero or more lvalues).
my $hash_ref = #{$result};
is the same as
my #array = #{$result};
my $hash_ref = #array;
This forces the array to be evaluated in scalar context by the assignment operator, which causes it to evaluate as the number of items in the array, or 1.

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.