Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does an uninitialized hash key have a default value of zero in Perl?

I have Perl code similar to the following:

# -- start --

my $res;

# run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{
    if( $row->[4] =~ /PA/ ) {
        $res->{ipv6}{pa}{$row->[2]}++;
    } elsif( $row->[4] eq 'PI' ) {
        $res->{ipv6}{pi}{$row->[2]}++;
    }
}

# -- stop --

At no point is $res ever set prior to iterating over the query results yet the code runs just fine.

When I put print statements before each value I get blanks in both cases but if the print statements come after the increment has been applied I get a value of >= 1 depending on how many IPv6 resources the organization has.

My question is, do I take this to mean an uninitialized hash key in Perl automatically has a value of zero?

Sorry if it comes across as a newbie question but I'm just not familiar with such a construct i.e. $hashref->{foo}->{bar}++ where a value has yet to be explicitly assigned to $hashref->{foo}->{bar}. Thanks in advance!

like image 446
freakwincy Avatar asked May 01 '09 14:05

freakwincy


2 Answers

The value is not automatically zero. The value is undefined initially. However, if you treat it like a number (eg, apply ++ to it), then Perl treats it like zero. If you treat it like a string (eg, apply . to it), then Perl treats it like an empty string.

From perldoc perlsyn, under 'Declarations':

The only things you need to declare in Perl are report formats and subroutines (and sometimes not even subroutines). A variable holds the undefined value ("undef") until it has been assigned a defined value, which is anything other than "undef". When used as a number, "undef" is treated as 0; when used as a string, it is treated as the empty string, ""; and when used as a reference that isn’t being assigned to, it is treated as an error.

like image 135
Telemachus Avatar answered Sep 20 '22 03:09

Telemachus


To elaborate on Telemachus' post, the uninitialized values will be undefined. The deep parts of the structure are autovivified. This is a handy feature where data structures are created for you automatically. Autovivification is great when you want it, but it can be a pain when you want to prevent it. There are many tutorials, articles and posts around the net on understanding autovivification.

So given an undefined $ref and $ref->{ipv6}{pa}{'foo'}++, $ref will be assigned a value of:

$ref = { 
     ipv6 => { 
          pa => { 
              foo => undef
          }
     }
};

Then the undef will be incremented, since undef numifies to 0, we get 0++ which is 1. For a final result of: ref->{ipv6}{pa}{'foo'} == 1.

If you have warnings enabled, (you do use warnings;, don't you?) you will get an "uninitialized value" warning when you operate on these undefined values. If it is the desired behavior to increment the unitialized value, then you can turn the desired group of warnings off over a limited part of your code:

use strict;
use warnings;
my $res;

// run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{   no warnings 'uninitialized';
    if( $row->[4] =~ /PA/ ) {
        $res->{ipv6}{pa}{$row->[2]}++;
    } elsif( $row->[4] eq 'PI' ) {
        $res->{ipv6}{pi}{$row->[2]}++;
    }
}

You can find the warnings hierarchy in perllexwarn.

like image 29
daotoad Avatar answered Sep 21 '22 03:09

daotoad