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";
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 ],
);
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.
It also has to be in an lvalue context. my @copy = @{ $undef }; will not autovivify.
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