Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Hash reference undefined somewhere?

by bowei_99 (Friar)
on Mar 09, 2011 at 21:59 UTC ( [id://892286]=perlquestion: print w/replies, xml ) Need Help??

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

update: I'm using 'use strict; use warnings' now, but now the issue is that the ProcessFile subroutine, when %do_for is defined, it goes through and executes each subroutine. I'd expected it to only run later, when I run $do_for{$what_to_do} explicitly. I'd like to use this instead of a cascading if... thoughts?

I'm having a problem with a hash assignment, and I'm sure it's something trivial, but I'm not seeing it. The indexes and values in the hash are all defined, so I can't see why Perl is complaining.

I have this chunk of code to process different actions:

my %do_for = ( get_hosts => GetHosts($_, \%data), get_new_fw_rules => GetNewFWRules($_, \%data), ); #print "while\n"; if ( ! $do_for{$what_to_do} ) { warn "ERR - what to do $what_to_do"; };

and the GetHosts sub is:

sub GetHosts { my ($line, $ref_data) = @_; my ($hostname, $old_ip, $new_ip) = split /,/, $line; print "here GetHosts - " . Dumper($ref_data) . "\n"; if ($old_ip) { print "here old ip $old_ip, hostname $hostname, new ip $new_ip + \n"; my $ref_data->{$old_ip}{"hostname"} = $hostname; my $ref_data->{$old_ip}{"new_ip"} = $new_ip; } }

and when I run it, I get this:

here GetHosts - $VAR1 = {}; ere old ip a-valid-ip-here, hostname valid-hostname-here, new ip vali +d-ip-here Can't use an undefined value as a HASH reference at ./fw-rule-convert. +pl line 60, <$IN_FH> line 1. Can't use an undefined value as a HASH reference at ./fw-rule-convert. +pl line 65, <$IN_FH> line 1.

But I don't understand - the only undefined value is the hash itself, which I'm trying to add to; I think that should be OK. The values from the split are in fact the correct values in the first line in the input file, and are not null.

Anybody have thoughts as to why I'm getting this error?

-- Burvil

Replies are listed 'Best First'.
Re: Hash reference undefined somewhere?
by wind (Priest) on Mar 09, 2011 at 22:03 UTC
    It doesn't appear that GetHosts actually returns explicitly. Trying assigning your functions to temporary variables that you can debug first:
    my $get_hosts = GetHosts($_, \%data); my $get_new = GetNewFWRules($_, \%data); print "Do I equal what you think i do? get_hosts = '$get_hosts'\n"; print "Do I equal what you think i do? get_new = '$get_new'\n"; my %do_for = ( get_hosts => $get_hosts, get_new_fw_rules => $get_new, );
    If for example, the functions are supposed to return arrays, you might need the following:
    my %do_for = ( get_hosts => [GetHosts($_, \%data)], get_new_fw_rules => [GetNewFWRules($_, \%data)], );
      I tried that, and I still get the same thing. I think the issue is that it's getting into the subroutine, but erroring out in that subroutine, so it never exits that subroutine, making it a moot point what it returns. This is what I did:

      Updated with debug statements:

      print "DEBUG: get_host: " . GetHosts($_, \%data) . "\n"; print "DEBUG: get_new_fw: " . GetNewFWRules($_, \%data) . "\n" +; my %do_for = ( get_hosts => GetHosts($_, \%data), get_new_fw_rules => GetNewFWRules($_, \%data), ); #print "while\n"; print "DEBUG: do_for: " . $do_for{$what_to_do} . "\n";
      and added return values to the subroutine:

      sub GetHosts { .... return 1; }

      I get the same error and output as before, and none of the new debug statements are printed.

      -- Burvil

Re: Hash reference undefined somewhere?
by GrandFather (Saint) on Mar 09, 2011 at 23:20 UTC

    Always use strictures (use strict; use warnings;)!

    GetHosts takes a reference parameter which you assign to a local variable $ref_data. Later in the same function you redefine the variable twice (inside the if)! That is three different variables using the same name in the same function. That can not be right. With strictures on you would get:

    "my" variable $ref_data masks earlier declaration in same scope at ... Use of uninitialized value $new_ip in concatenation (.) or string at . +..

    which happens to tell you exactly where the problems are. Did I mention "Always use strictures (use strict; use warnings;)" already? You really, really should.

    True laziness is hard work
      Actually, I got it - I changed it to this
      if ($old_ip) { print "here old ip $old_ip, hostname $hostname, new ip $new_ip + \n"; $ref_data->{$old_ip}{"hostname"} = $hostname; $ref_data->{$old_ip}{"new_ip"} = $new_ip; }
      which works now. I knew it was something trivial. :)

      -- Burvil

        But are you using strictures now?

        True laziness is hard work
      Great! I'm just not sure how to get around this.... I do have the following at the top level, in main:

      my $ref_data = ProcessFile($fh, "get_hosts");
      I also have $ref_data defined in the GetNewFWRules subroutine in the same way I have for GetHosts. But aren't all of those declarations in different scopes, i.e. main vs. a subroutine?

      Either way, I changed the declaration in main to $ref_data2, and I still get the same thing. There are no other declarations of $ref_data.

      -- Burvil

Re: Hash reference undefined somewhere?
by Argel (Prior) on Mar 10, 2011 at 22:30 UTC
    update: I'm using 'use strict; use warnings' now, but now the issue is that the ProcessFile subroutine, when %do_for is defined, it goes through and executes each subroutine. I'd expected it to only run later, when I run $do_for{$what_to_do} explicitly. I'd like to use this instead of a cascading if... thoughts?
    Calling a subroutine is calling a subroutine. Why would you expect it to somehow magically create a subroutine reference and not execute the code?? It's just in list context -- the '=>' is just a special form of the comma that usually lets you get way with using barewords to the left of it. For anything to the right of it there is really no difference between '=>' and ','.

    It's similar to what you do later on:

    print "here GetHosts - " . Dumper($ref_data) . "\n";

    Which can be rewritten with commas like below (which in theory performs better because concatenation can be expensive, especially when it's unnecessary):

    print "here GetHosts - ", Dumper($ref_data), "\n";

    Now, you would expect Dumper to actually be called here vs. creating a reference to it, right? Right?? So what you need to do is create subroutine references ('\&') like in the following (untested; based on some really old code):

    my %do_for = ( get_hosts => \&GetHosts, get_new_fw_rules => \&GetNewFWRules, ); #... $do_for({$what_to_do}->( $_, \%data );

    Elda Taluta; Sarks Sark; Ark Arks

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://892286]
Approved by sundialsvc4
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (6)
As of 2024-04-16 10:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found