I was surprised by one aspect of Perl’s autovivification a few weeks ago, and I’m surprised it’s taken over 20 years for me to run into it.

I’m used to autovivification being a handy thing when working with, for example, hashes of arrayrefs. Here I’m using autovivification to create hash entries in %users_by_category whenever a new one is added.

my %users_by_category;
for my $user ( @users ) {
    my $category = categorize($user);

    push @{$users_by_category{$category}}, $user;

This saves from having to do the tedious equivalent:

if ( not exists $users_by_category{$category} ) {
    $users_by_category{$category} = [];
push $users_by_category{$category}, $user;

Autovivification doesn’t work just because you dereference an undef value. For example:

my $x;
my $n = scalar @{$x};

Can't use an undefined value as an ARRAY reference at ...

The push in the first example works because using @{$users_by_category{$category}} in a push makes it an “lvalue”, meaning it’s a value that can appear on the left side of an assignment operator, or something that can be assigned to.

What surprised me is that map, grep, for and function calls are all lvalue context.

They’re lvalues because in all those cases, the value of the array being passed can be modified. It makes perfect sense when I thought about it, but I’d never run into it.

Here’s an example with grep:

my $x;
grep {1} @{$x};
say "x is $x";

x is ARRAY(0x1e29fc8)

Or even just a regular function call:

sub foo {}
my $x;
say "x is $x";

x is ARRAY(0x1059fc8)

To help protect against autovivification in your code when you’re not expecting it, you can look at the autovivification pragma available on CPAN.

Thanks to Leon Timmermans and Paul Evans for their input.