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

Hi,

When I let a sub return a reference to a not existing element in a hashref in a hashref, perl yields the "Use of uninitialized value" warning.
However, I would expect it to be created automatically.

#!/usr/bin/perl -wl use strict; my $hashref = { foo => { bar => 'xyzzy' } }; sub name_me { # Note: there is no $hashref->{foo}{foo} return \ $hashref->{foo}{foo}; } print ${ name_me() }; # Note: I narrowed it down to this code. The original code # was about 50 lines. Because this is just a fragment, I couldn't # think of a proper name for the sub. Sorry :)

The weird thing is, that if i put the hashref in the dereference, or if i have a single-layered $hashref, it doesn't show the warning. Why is perl showing a warning with the above script?

2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

Replies are listed 'Best First'.
Re: Autovivification not working?
by MZSanford (Curate) on Dec 20, 2001 at 14:47 UTC
    I believe this message is cause by the warning's pragma (-w), to alert you to the printing of an undefined value, not the returning of one. To test this thoery, i used the following :
    #!/usr/bin/perl -wl use strict; my $hashref = { foo => { bar => 'xyzzy' } }; sub name_me { # Note: there is no $hashref->{foo}{foo} return \ $hashref->{foo}{foo}; } $a = name_me(); print $a; print $$a; print ${ name_me() }

    This, on my machine, prints the following :
    SCALAR(0x184068) Use of uninitialized value in print at bar.pl line 15. Use of uninitialized value in print at bar.pl line 17.

    $ perl -e 'do() || ! do() ;' Undefined subroutine &main::try
Re: Autovivification not working?
by larryk (Friar) on Dec 20, 2001 at 14:49 UTC
    because the autovivified element has no value. it is being created though as you can see by adding...
    use Data::Dumper; print Dumper($hashref); # or even just print 'success' if exists $hashref->{foo}{foo};
    additionally, if you put use diagnostics; at the top of your script you will get extended warnings which may help.
       larryk                                          
    perl -le "s,,reverse killer,e,y,rifle,lycra,,print"
    
Re: Autovivification not working?
by Juerd (Abbot) on Dec 20, 2001 at 16:33 UTC
    Thanks, all who replied. However, I forgot something while trying to narrow it down. One of the hashes is a tie()d array, and that's what goes wrong for some reason.

    So much for trying to find out where it goes wrong. Here's the real script:
    2;0 juerd@ouranos:~$ rm karmatest 2;0 juerd@ouranos:~$ perl test.pl Use of uninitialized value in addition (+) at test.pl line 31. 2;0 juerd@ouranos:~$ cat test.pl #!/usr/bin/perl -w package Karma; use GDBM_File; use strict; sub new($$){ my ($prot, $file) = @_; my $self = { hash => {} }; $self->{object} = tie %{ $self->{hash} }, 'GDBM_File', $file, GDBM +_WRCREAT, 0640; bless $self, $prot; return $self; } sub resolve($$){ my ($self, $subject) = @_; $subject = lc $subject; my $recur = 0; if (defined $self->{hash}{$subject}){ while ($self->{hash}{$subject} =~ /^S:(.*)/){ $subject = 'ERECURSIE', last if ++$recur > 10; $subject = lc $1; } } # The next line was put in to work around the warning. # $self->{hash}{$subject} = 0 unless defined $self->{hash}{$subject} +; return \ $self->{hash}{$subject}; } sub incr($$;$){ my ($self, $subject, $d) = @_; #line 31 return ${ $self->resolve($subject) } += defined($d) ? $d : 1; } sub decr($$;$){ my ($self, $subject, $d) = @_; return ${ $self->resolve($subject) } -= defined($d) ? $d : 1; } sub get($$){ my ($self, $subject) = @_; my $foo = ${ $self->resolve($subject) }; print "BLAAT: $foo\n"; return $foo; } sub set($$$){ my ($self, $subject, $new) = @_; return ${ $self->resolve($subject) } = $new; } sub reorganize($){ $_[0]->{object}->reorganize(); } 1; package main; my $karma = Karma->new('karmatest'); $karma->incr('foo'); # foo must not exist

    I'm sorry to have disappointed you by leaving out a very important part.

    2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

      It's still the same deal. Your hash element has been autovivified and set to undef. This is what the warning is - you are using the undef as a number. If your hash had not been autovivified, your would have received a "Expected reference...." error when trying to access the value.

      The way you have avoided the warning is the correct way to do it, although you can be slightly more compact with:

      $self->{hash}{$subject} ||= 0;

      In summary, you are trying to fix the wrong problem. Perl isn't being tricky this time. All it's doing is warning you that it is turning an 'undef' into a '0' for the addition. This is what you want.

      ____________________
      Jeremy
      I didn't believe in evil until I dated it.

        --, ++, -=, += and friends shouldn't complain about undefined variables, according to documentation.
        That's why perl -wMstrict -e'my $a = undef; $a++;' does not complain, nor does $hash{foo}++.

        But when the hash in quesion is tied AND a hashref AND in another hash, perl suddenly _does_ complain.
        I tried narrowing it down to the essential bits again, succesfully this time.
        As you can see in the paste below, everything is fine with the second one, which would be exactly the same if it were tie()d.

        2;0 juerd@ouranos:~$ cat test.pl #!/usr/bin/perl -w use GDBM_File; use strict; unlink 'karmatest'; my $hashref = { hash => {} }; $hashref->{object} = tie %{ $hashref->{hash} }, 'GDBM_File', 'karmates +t', GDBM_WRCREAT, 0640; sub resolve { return \ $hashref->{hash}{$_[0]}; } # Warning! ${ resolve('this one does not exist') } += 2; # now, the same, but without tie: my $second = { hash => {} }; sub resolve_again { return \ $second->{hash}{$_[0]}; } # No warning! ${ resolve('this one does not exist') } += 2; 2;0 juerd@ouranos:~$ perl test.pl Use of uninitialized value in addition (+) at test.pl line 13.


        I think my inability to express what I mean in English is the biggest problem here :(

        2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

Re: Autovivification not working?
by Juerd (Abbot) on Dec 20, 2001 at 14:53 UTC
    Oops, I didn't even mean to use print there.

    Think of that line as if it were ${ name_me() } += 3, as "+=" should be a "don't care" (no warning about undef values) operator.

    2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

      Tried '++', and '+=3', and got no warning on either (5.6.1).