icanhezperl has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I'm seeing an odd behavior wehere the "Can't use an undefined value as an ARRAY reference at ..." is generated when expected but not when map() and grep() are involved.

Here's the code. In the first case with map(), perl runs without an error (ditto for grep). But in the second case, without any map or grep, the expected error is thrown becaus the value being dereferenced is undefined.

use strict; use warnings; my $this_key = "NOT_IN_HASH"; my $hash_ref = {}; my @items; if (0) { # this gives no error @items = map { $_->{value} } @{$hash_ref->{$this_key}}; } else { # but this generates to the expected error. @items = @{$hash_ref->{$this_key}}; }

Am I missing something obvious? Is this behavior intentional?

Thank you.

  • Comment on map() and grep() suppress "Can't use an undefined value as an ARRAY reference at ..." errors
  • Download Code

Replies are listed 'Best First'.
Re: map() and grep() suppress "Can't use an undefined value as an ARRAY reference at ..." errors
by stevieb (Canon) on Mar 15, 2018 at 20:47 UTC

    This is due to the way that map does aliasing (it's essentially using a for() loop). What's happening is that the aref is being used in l-value context, and therefore is being auto-vivified into existence.

    In your latter example, you're attempting to use the aref directly in r-value context, which is why it generates the error (because no auto-vivification happens).

    You can simplify your test to use for(), and you'll get the same result as with map():

    use warnings; use strict; my $x; for (@{ $x }){ print "$_\n"; }

    ...no output. To visually see that $x was auto-vivified as an array reference, you can use the ref() function:

    my $x; my @a = map $_, @{ $x }; print ref $x;

    Output:

    ARRAY

    Disclaimer: taken verbatim from one of my previous StackOverflow answers.

Re: map() and grep() suppress "Can't use an undefined value as an ARRAY reference at ..." errors
by haukex (Archbishop) on Mar 15, 2018 at 20:48 UTC
      stevieb beat me to it :-)

      By only mere seconds bud ;)

Re: map() and grep() suppress "Can't use an undefined value as an ARRAY reference at ..." errors
by Marshall (Canon) on Mar 15, 2018 at 21:16 UTC
    I translated your map{} into the equivalent foreach() statement.
    All map statements have an equivalent for() or foreach() loop.
    use strict; use warnings; use Data::Dumper; my $this_key = "NOT_IN_HASH"; my $hash_ref = {}; my @items; @items = map { $_->{value} } @{$hash_ref->{$this_key}}; print Dumper \@items; my @x; foreach (@{$hash_ref->{$this_key}}) # loop does not execute # because array is empty { print "loop is looping\n"; #This doesn't ever print ! push @x, $_->{value}; } print Dumper \@x; my @nothing; print Dumper \@nothing; __END__ Prints: $VAR1 = []; #print Dumper \@items; $VAR1 = []; #print Dumper \@x; $VAR1 = []; #print Dumper \@nothing;
Re: map() and grep() suppress "Can't use an undefined value as an ARRAY reference at ..." errors
by icanhezperl (Novice) on Mar 15, 2018 at 21:06 UTC
    Thank you both for the quick responses and pointers to the workings of Perl's subtle magic.