Perl vivification question while dereferencing und

2019-01-23 14:09发布

问题:

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.

回答1:

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).



回答2:

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.



回答3:

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.