Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Array dereference in foreach()

by pme (Parson)
on Nov 14, 2017 at 13:58 UTC ( #1203377=perlquestion: print w/replies, xml ) Need Help??
pme has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

This tiny code fails with "Can't use an undefined value as an ARRAY reference" exception.

use strict; use warnings; use diagnostics; my $href = { list => undef, }; my @a = @{$href->{list}}; # fails here foreach my $i (@a) { print "$i\n"; }
but this one works as expected (does nothing)
use strict; use warnings; use diagnostics; my $href = { list => undef, }; foreach my $i (@{$href->{list}}) { print "$i\n"; }
Could you explain me what makes the difference here? Thanks.

My perl is 5.18.2.

Replies are listed 'Best First'.
Re: Array dereference in foreach()
by haukex (Monsignor) on Nov 14, 2017 at 14:10 UTC

    From perlref (emphasis mine): "... references could spring into existence when in an lvalue context. ... This process is called autovivification." foreach provides lvalue context to what it is looping over: "If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. ... the foreach loop index variable is an implicit alias for each item in the list that you're looping over."

    $ perl -wMstrict -MData::Dump -e ' @{$a->{list}} = (); dd $a' { list => [] } $ perl -wMstrict -MData::Dump -e ' for (@{$a->{list}}) {}; dd $a' { list => [] } $ perl -wMstrict -MData::Dump -e ' my @x = @{$a->{list}}; dd $a' Can't use an undefined value as an ARRAY reference at -e line 1.
      In your third one-liner example, $a plausibly could be undefined. I think that the OPs problem is that an array-type variable, @a, is being assigned an array reference, $href. Not sure why Perl is complaining about an "undefined variable" in that case, however.
        I think that the OPs problem is that an array-type variable, @a, is being assigned an array reference, $href.

        Sorry, but that's not the right way to look at it. @a is not being assigned a reference, instead, the @{...} dereferences the array reference, and it can be used in place of any normal array (perlref), so in effect my @x = @{...} is like assigning an array to an array.

        In your third one-liner example, $a plausibly could be undefined.

        I'm not sure what you mean, $a is initially undefined in every example. Autovivification is what is causing both $a to go from being uninitialized to holding a hashref (because it's being dereferenced as such with ->{...}) and $a->{list} to come into existence as a hash entry with a value of [] (empty array ref). The third example does not work because in my @x = @{$a->{list}};, the @{$a->{list}} is not in lvalue context. Personally, I think in this case the autovivification behavior is fairly consistent with DWIM:

        • In @x = @{$a->{list}}, I am asking Perl to access and dereference a reference, but there is no such reference there - the thing I expected to be there isn't, so Perl complains.
        • In @{$a->{list}} = (), I am explicitly telling Perl that I want to assign something to that reference and I want it to be an array reference, so it makes sense for that thing to come into existence.
        • The only "potentially surprising" thing here is the foreach behavior, which I explained in the first reply.

        Edit: Just moved a sentence so the order makes more sense.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1203377]
Approved by Corion
Front-paged by Eily
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (9)
As of 2017-11-22 08:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    In order to be able to say "I know Perl", you must have:













    Results (316 votes). Check out past polls.

    Notices?