http://www.perlmonks.org?node_id=1203576


in reply to Re^3: Array dereference in foreach()
in thread Array dereference in foreach()

Hi haukex,

Thank you to for your detailed explanation. That makes sense. However I found another interesting feature.

my $h; my $g; $h->{abc} = $g->{lkj}; print "h: ", Dumper(\$h), "\n"; print "g: ", Dumper(\$g), "\n";
and the output is
h: $VAR1 = \{ 'abc' => undef }; g: $VAR1 = \{};
The left side ($h) is autovivified and undef is assigned to key 'abc'. It is correct. But what has happened on the right? Is it semi-autovivified or what? Empty anonymous hashref is assigned to $g. Where is 'lkj'? Is $g->{lkj} in lvalue context? Why there is no exception?

Regards

Replies are listed 'Best First'.
Re^5: Array dereference in foreach()
by choroba (Cardinal) on Nov 16, 2017 at 10:20 UTC
    That's how autovivification currently works. In order to assign the value to the LHS, you need to look what's in $g->{lkj}. To check for the existence of the key, you first need $g to be a hash reference, if it's undef, it autovivifies, else if it's not a hash ref, you get an exception (under strict). There's no need to create the lkj key in $g, as it wasn't used in an lvalue context, but if you tried to access $g->{lkj}{mno} or $g->{lkj}[2] ...

    Use

    no autovivification;

    if you don't want the structures to be created. See autovivification.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      If $g is autovivified when it is on the right side of equal sign I just don't get why this throws exception.
      my $a; my @b = @$a;
      and why this one works smoothly
      my $a; foreach (@$a) { print "$_\n"; }
        Note that $a gets autovivified into [] after for (@$a) -- that's because for creates a special context similar to lvalue (as its list's elements are aliased to the loop variable).

        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
        why this throws exception ... my @b = @$a; ... and why this one works smoothly ... foreach (@$a) { }

        I hope that my earlier explanations, about why my $x; my $y = @$x; throws an error but my $x; @$x = (); does not, make sense? Do you see how in the second example, @$x is in "lvalue context", that is, it is on the left-hand side of the assignment?

        foreach is kind of special, it aliases the loop variable to the things it is looping over. In the following, see how $val becomes an alias for each of the variables in turn and the original values $x,$y,$z are modified via $val:

        my ($x,$y,$z) = ('x','yy','zzz'); for my $val ($x,$y,$z) { $val = $val . length($val); } print "$x/$y/$z\n"; # prints "x1/yy2/zzz3"

        Loosely speaking, this is why the variables foreach (...) is looping over are treated by Perl as if they were on the left-hand side of an assignment (lvalue context), and why the autovivification behavior is applied to them.

Re^5: Array dereference in foreach()
by 1nickt (Canon) on Nov 16, 2017 at 12:19 UTC

    Hi, on a side note, you don't need to pass to Data::Dumper a reference to the structure you are dumping, if that structure is already a reference.

    my %hash = ( foo => 'bar' ); my $href = { baz => 'qux' }; print " hash: ", Dumper( \%hash ), "\n"; print "hashref: ", Dumper( $href ), "\n";

    Hope this helps!


    The way forward always starts with a minimal test.