Can anyone explain the push
statement in the following Perl code to me? I know how push in perl works but I can't understand what the first argument in following push command represents. I am trying to interpret someone's script. I tried to print "@a\n";
but it only printed ARRAY(0x9aa370)
which makes me think that the push is not doing anything. Any help is appreciated. Thanks!
my @a = ();
my $b = 10;
my $c = 'a';
push(@{$a[$b]}, $c);
Let's break it down.
The @{...}
is understood from "Using References" in perlref
Anywhere you'd put an identifier (or chain of identifiers) as part of a variable or subroutine name, you can replace the identifier with a BLOCK returning a reference of the correct type.
So what is inside { ... }
block had better work out to an array reference. You have $a[$b]
there, an element of @a
at index $b
, so that element must be an arrayref.
Then @{...}
dereferences it and push
es a new element $c
to it. Altogether, $c
is copied into a (sole) element of an anonymous array whose reference is at index $b
of the array @a
.
And a crucial part: as there is in fact no arrayref † there, the autovivification kicks in and it is created. Since there are no elements at indices preceding $b
they are created as well, with value undef
.
Now please work through
tutorial perlreftut and
data-structures cookbook perldsc
while using perlref
linked in the beginning for a full reference.
With complex data structures it is useful to be able to see them, and there are tools for that. A most often used one is the core Data::Dumper, and here is an example with Data::Dump
perl -MData::Dump=dd -wE'@ary = (1); push @{$ary[3]}, "ah"; dd \@ary'
with output
[1, undef, undef, ["ah"]]
where []
inside indicate an arrayref, with its sole element being the string ah
.
† More precisely, an undef
scalar is dereferenced and since this happens in an lvalue context the autovivification goes. Thanks to ikegami for a comment. See for instance this post with its links.
Let's start with the following two assertions:
@a
starts out as an empty array with no elements.$b
is assigned the value of 10.Now look at this construct:
@{$a[$b]}
To understand we can start in the middle: $a[$b]
indexes element 10 of the array @a
.
Now we can work outward from there: @{...}
treats its contents as a reference to an array. So @{$a[$b]}
treats the content of element 10 of the array @a
as a reference to an anonymous array. That is to say, the scalar value contained in $a[10]
is an array reference.
Now layer in the push:
push @{$a[$b]}, $c;
Into the anonymous array referenced in element 10 of @a
you are pushing the value of $c
, which is the character "a". You could access that element like this:
my $value = $a[10]->[0]; # character 'a'
Or shorthand,
my $value = $a[10][0];
If you pushed another value into @{$a[10]}
then you would access it at:
my $other_value = $a[10][1];
But what about $a[0]
through $a[9]
? You're only pushing a value into $a[$b]
, which is $a[10]
. Perl automatically extends the array to accommodate that 11th element ($a[10]
), but leaves the value in $a[0]
through $a[9]
as undef
. You mentioned that you tried this:
print "@a\n";
Interpolating an array into a string causes its elements to be printed with a space between each one. So you didn't see this:
ARRAY(0xa6f328)
You saw this:
ARRAY(0xa6f328)
...because there were ten spaces before the 11th element which contains an array reference.
If you were running your script with use warnings
at the top, you would have seen this instead:
Use of uninitialized value in join or string at scripts/mytest.pl line 12.
Use of uninitialized value in join or string at scripts/mytest.pl line 12.
Use of uninitialized value in join or string at scripts/mytest.pl line 12.
Use of uninitialized value in join or string at scripts/mytest.pl line 12.
Use of uninitialized value in join or string at scripts/mytest.pl line 12.
Use of uninitialized value in join or string at scripts/mytest.pl line 12.
Use of uninitialized value in join or string at scripts/mytest.pl line 12.
Use of uninitialized value in join or string at scripts/mytest.pl line 12.
Use of uninitialized value in join or string at scripts/mytest.pl line 12.
Use of uninitialized value in join or string at scripts/mytest.pl line 12.
ARRAY(0xa6f328)
...or something quite similar.
Your structure currently looks like this:
@a = (undef,undef,undef,undef,undef,undef,undef,undef,undef,undef,['a'])
If you ever want to really get a look at what a data structure looks like, rather than using a simple print, do something like this:
use Data::Dumper;
print Dumper \@a;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With