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

The homework assignment seemed easy enough, create a class that reads in a file, generates a hash file, actually HOH, passes it back and do stuff to the hash file. I thought I had everything working until I decided to test out creating a new OBJ from an existing one. Actually not a part of the assignment, but we were supposed to allow for it, and having written the code I thought I'd test it, only to find out that having created the hash, returned it to main, and called another method the Hash seemed to have dissapeared. The basic print statements say that I'm generating a hash, it's the same hash in main, and the again the same has in the module. But when I try to access the data in it, nothings there. With not enough PERL under my belt yet, I can't see what must be something basic that I've overlooked. Perhaps someone can be of assistance, as nothing in the FAQ's seem to deal with thos particular problem. Thanks in advance for any advice you can offer.
#!/bin/perl use lib ("."); use Rainfall; $weather = Rainfall->new('$infile'); $storms = $weather->new(); # clone Rainfall : #!/bin/perl package Rainfall; sub new { my $type = shift; my $class = ref($type) || $type; my ($States,$other) =({}, {}); my ($infile,$key1,$key2,$ary,$city,$state); my $clone = (["clone"]); if (@_) { $infile = $ARGV[0]; # get input weather filename open (infl,"<$infile") || die "Cannot open $infile \n"; while (<infl>) #read the whole { ($state, $city, $ary) = (split/:/); # speperate the state $state = ucfirst $state; $city = ucfirst $city; $States{$state}{$city} = $ary; #Build hash file } close (infl) || die("$infile can't be closed:$1"); bless $States, $class; print "new is $States\n"; foreach $state (sort keys %States) { foreach $city (sort keys %{$States{$state}}) { $str = join(",",$state,$city); printf "%-30s %s\n ",$str,$States{$state}{$city}; } } } elsif (ref $type) { foreach $key1 (keys %$type) { print "clone k1 $key1\n"; #<=== This never happens foreach $key2 (keys %{$type{$key1}}) { $other{$key1}{$key2} = $type{$key1}{$key2}; print "k1 $key1 k2 $key2 \n"; } } print "cloning $type to $other\n"; bless $other,'Rainfall'; foreach $state (sort keys %other) { foreach $city (sort keys %{$other{$state}}) { $str = join(",",$state,$city); printf "%-30s %s\n ",$str,$other{state}{$city}; } } } else { bless {}, 'Rainfall'; } return ref($type) ? $other : $States; }
Data would be State:city:1.2 2.1 3.4 ...

Replies are listed 'Best First'.
Re: Obj ref to %hoh
by ChemBoy (Priest) on Oct 28, 2001 at 08:28 UTC

    You're very close--just one problem is screwing you up. You create a hash reference called $States, bless it and return it as your new object. Unfortunately, you do your initialization code on a hash called %States, which is sadly completely unrelated to $States. If you add a line like

    print "DEBUGGING: \n", join ",", keys %$weather;
    after your object creation code, you'll see that your object has no data in it. (Alternatively, take a good look at it using the Perl Debugger, which makes it very easy to view data structures and see if they contain what you think they should).

    The solution for this particular problem is to make one simple change:

    $States{$state}{$city}
    becomes
    $States->{$state}{$city}

    You will then have to debug your debugging code, as well, but I can see from the rest of your code that you already know what the correct syntax for reading from a hash reference is, so I won't bother you with that.

    What I will bother you with is what could have prevented this problem in the first place: use strict;. Had you tried compiling Rainfall.pm under strict, you would have gotten the following error message from line 21 (or thereabouts):
    Global symbol "States" requires explicit package name Which would have told you, in turn, that the "States" in that line was not the "States" you thought you were working with. And saved you all sorts of debugging time, too. :-)

    Welcome to the Monastery, and good luck!



    If God had meant us to fly, he would *never* have given us the railroads.
        --Michael Flanders

      Actually at one point I was using strict and did indeed get that error, but I never could figure out exactly what it ment nor get it to resolve. But I now have things working, and can go to vespers with a clear conscience, and then start studying for tomorrows mid-term. Thanks for your help
Re: Obj ref to %hoh
by Anonymous Monk on Oct 28, 2001 at 07:56 UTC
    Oy, there's a couple of places to start here...

    1) "use strict;" and -w ... once i turned both of those things on, a bunch of little errors became obvious.

    2) ARGV refers to your programs args, not your methods args, so you were getting lucky that "new" knew how to open $infile.

    3) The difference between $foo and %foo...
    This is sometimes a hard thing for people to grasp, but even though you refrence individual valuse of %foo as $foo{bar}, doesn't mean $foo is related.
    I think your core problem is that you are never acctually creating the first hash -- even though your print statements make you think you do.
    By declaring "my ($States,$other) =({}, {});" you are initializing $States as a hash ref, but when you then refer to "$States{$state}{$city} = $ary;" you aren't doing anything with your hash ref, you are now using the (previously undeclared) global hash %States ...
    Your print statements misslead you because they are refering to %States as well!

    (BTW: use strict & -w would have pointed those out to you, when I turned them on I got "Global symbol "%States" requires explicit package name at perlmonks.pl line XXX." which is what typed me off.)

    take a look at the perlref man page for more info on how to use hash refs.