I'm having tough time in understanding why the following works:
my $array_reference;
foreach $element (@{$array_reference}) {
# some code
}
while the following does not work
my $array_reference;
if (scalar (@{$array_reference}) {
# some code here
}
I understand that perl brings to life (auto-vivifies) undefined reference. But I am still confused as in why the latter code segment throws FATAL.
Dereferences autovivify in lvalue context (meaning when a modifiable value is expected), and foreach create an lvalue context.
>perl -E"$$x = 1; say $x;"
SCALAR(0x74b024)
>perl -E"++$$x; say $x;"
SCALAR(0x2eb024)
>perl -E"\$$x; say $x;"
SCALAR(0x30b024)
>perl -E"sub {}->($$x); say $x;"
SCALAR(0x27b03c)
>perl -E"for ($$x) {} say $x;"
SCALAR(0x25b03c)
The last two create an lvalue context because they need a value to which to alias $_[0]
and $_
(respectively).
Perl has inconsistencies in this area, but in general, code that may modify a structure autovivifies, while code that won't doesn't. And if it doesn't autovivify, it is trying to dereference an undefined value, which triggers a warning, or, under use strict "refs"
, an exception.
I think, looking at perlref, that this is expected behaviour:
"References of the appropriate type can spring into existence if you dereference them in a context that assumes they exist."
A similar thing to foreach happens with push() and friends:
my $f;
push @$f, 1;
say @$f;
Although not with the new, can-just-take-a-reference versions:
my $f = [];
push $f, 1;
say @$f;
works, while
my $f;
push $f, 1;
say @$f;
does not, which I think is sensible as push has no idea what you really meant there.
The interesting question is should scalar(@$undef) do the same thing, or should warn, as it eventually returns undef, I think it might as well warn right away.