I\'m getting the error Can\'t use an undefined value as an ARRAY reference
in a Perl script. Below is a highly simplified version.
Basically I have setup a
So you need to check if $data_for{$letter}
is a reference or not. Possible checks:
exists($data_for{$letter})
.defined($data_for{$letter})
because a non-existent hash element is undefined.$data_for{$letter}
because references are always true.We can use the check to provide us something to dereference:
sort @{ $data_for{$letter} // [] }
We can use the check to avoid dereferencing at all.
sort $data_for{$letter} ? @{ $data_for{$letter} } : ()
This gives us the following:
print "$letter: ";
for my $item ( sort $data_for{$letter} ? @{ $data_for{$letter} } : () ) {
print "$item, ";
}
print "\n";
Or better yet, we can avoid the trailing ,
with the following:
use feature qw( say );
say "$letter: ", join ", ", sort $data_for{$letter} ? @{ $data_for{$letter} } : ();
It works just fine if I DON'T sort the data array.
When you dereference an undefined variable that's used as a modifiable value (lvalue), Perl will automatically create a variable of the appropriate type, and it will place a reference to the newly created variable in the undefined variable. This is called "autovivification".
Since autovivifying only happens in lvalue context, derefencing an undefined value elsewhere leads to the an error.
my ($a,$b); # Both are undefined.
@$a = @b; # OK. Equivalent to @{ $a //= [] } = @b.
@a = @$b; # XXX. "Can't use an undefined value as an ARRAY reference."
sort
doesn't modify its operands, so it doesn't evaluate them in lvalue context.
A foreach loop evaluates its operands in lvalue context to allow for for (@$a) { $_ = uc($_); }
. That means that
for (@{ $data_for{$letter} }) { ... }
implicitly modifies $data_for{$letter}
as follows:
for (@{ $data_for{$letter} //= [] }) { ... }
$data_for{B}
is not defined, so the attempt to dereference it as an array (in the sort @{$data_for{$letter}}
expression) is an error.
One workaround is to assign a (empty) value for $data_for{B}
:
$data_for{'A'} = ['apple', 'astronaut', 'acorn'];
$data_for{'B'} = [];
$data_for{'C'} = ['car', 'cook', 'candy'];
but a more general workaround is to use the '||' operator (or '//' operator for Perl >=v5.10) to specify a default value when a hash value is not defined
foreach my $item ( sort @{$data_for{$letter} || []}) { ... }
When $data_for{$letter}
is undefined (and therefore evaluates to false), the expression $data_for{$letter} || []
evaluates to a reference to an empty array, and the array dereference operation will succeed.