Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array push and references

Tags:

perl

I am a beginner perl programmer and I've come across a piece of code which looks as follows:

my @Numbers=();

push(@{$Numbers[0]},3,8,9);
push(@{$Numbers[1]},5);

print join(",",@{$Numbers[0]});
print "\n";

print join(",",@{$Numbers[1]});
print "\n";

I'm having difficulty in understanding what the push onto @{$Numbers[0]} and @{$Numbers[1]} is doing. Does the push automatically create array references to [3,8,9] and [5] in the Numbers array? I have no difficulty in understanding the syntax below, which is far more common I suppose, but I haven't come across the syntax that I've pasted above, which I guess also uses auto-vivification to populate the Numbers array with references.

my @Numbers=();

push(@Numbers,[3,8,9]);
push(@Numbers,[5]);

print join(",",@{$Numbers[0]});
print "\n";

print join(",",@{$Numbers[1]});
print "\n";
like image 734
sdp Avatar asked Feb 20 '26 15:02

sdp


1 Answers

There are two features at play, and one is indeed autovivification.


I'll go into autovivification in a second. First, let's consider the fact that @Numbers is empty when we access $Numbers[0]. This is not a problem. Perl will automatically extend the array to include this element.[1]

my @a;
$a[3] = 123;          # ok!
print(Dumper(\@a));   # [ undef, undef, undef, 123 ]

This isn't what the documentation calls autovivification, but it's similar enough that some people will call it autovivification too.


As I mentioned, the second feature is indeed autovivification. Autovivification is the automatic creation of an anonymous variable through dereferencing. Specifically, it happens when dereferencing an undefined scalar.[2]

In this case, autovivification creates an array since @BLOCK is an array dereference. A reference to that array is created and stored in the previously-undef scalar.

In other words, autovivification makes

push @{ $ref }, LIST;

effectively equivalent to

push @{ $ref //= [] }, LIST;

or

if (!defined($ref)) {
   my @anon;
   $ref = \@anon;
}

push @$ref, LIST;

It was probably just a contrived example for the question, but note that the posted code is weird. We know $Numbers[0] and $Numbers[1] are undef, so we don't need push.

my @nums;
@{ $nums[0] } = ( 3, 8, 9 );    # Also autovivification.
@{ $nums[1] } = 5;

And since we know $Numbers[0] and $Numbers[1] are undef, we there's no point in relying on autovivification either.

my @nums;
$nums[0] = [ 3, 8, 9 ];
$nums[1] = [ 5 ];

Let's get rid of those hardcoded indexes.

my @nums;
push @nums, [ 3, 8, 9 ];
push @nums, [ 5 ];

And a final simplification.

my @nums = (
   [ 3, 8, 9 ],
   [ 5 ],
);

  1. This only happens in an lvalue context, meaning when the referenced variable is expected to be modified/modifiable. say $a[@a]; won't extend the array even though it accesses an element after its last element.

  2. It also has to be in an lvalue context. my @copy = @{ $undef }; will not autovivify.

like image 63
ikegami Avatar answered Feb 23 '26 12:02

ikegami



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!