16

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.

kuriouscoder
  • 5,394
  • 7
  • 26
  • 40
  • Good question. Note that the first sequence actually auto-vivifies the reference. So your script will work if the `if` comes after the `foreach`, but not vice-versa. I think this is just an obscure (undocumented?) detail of Perl, but I am curious to see the answers. – Nemo Jun 21 '11 at 02:20
  • nemo - I do not think execution would flow into foreach loop for undefined references. May be I'm missing something – kuriouscoder Jun 21 '11 at 02:27
  • No, execution does not flow "into" the loop, because the auto-vivified array is empty. But once you execute the `foreach` on the undefined reference, the reference is no longer undefined... So you can call `scalar @$reference` on it successfully. – Nemo Jun 21 '11 at 02:29
  • 2
    I'm surprised that the first (foreach) doesn't even warn. – Alex Jun 21 '11 at 02:32

3 Answers3

11

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

ikegami
  • 367,544
  • 15
  • 269
  • 518
7

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.

ysth
  • 96,171
  • 6
  • 121
  • 214
  • But `foreach` does not modify the variable; it just reads it. Yet it autovivifies... – Nemo Jun 21 '11 at 04:14
  • @Nemo, foreach does indeed take lvalues (modifiable values): `foreach (@$a) { $_ = uc($_) }` – ikegami Jun 21 '11 at 04:28
  • @ikegami: Aha, right, forgot about that. OK then I guess it is consistent. +1 to both responses. – Nemo Jun 21 '11 at 04:29
4

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.

Alex
  • 5,863
  • 2
  • 29
  • 46
  • "Expected behavior"? Meaning `foreach` "assumes they exist" but `scalar` does not? This looks like a seriously under-specified part of the Perl language. Could either of these examples change their behavior in version N+1? I honestly do not know. – Nemo Jun 21 '11 at 04:15