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

Hello.. I have a bit of an odd problem (I think its odd. It might not be). I've written a module that exports a single function. This function opens a file, reads in each line, and builds an assocative array based on whats coming in setup by doing my %data = { };. A simple unpack into an array and then $data{@field[0]}{@array[0]} = @array1; $data{@field1}{@array[0]} = @array2; and so on. Thus array[0] is like a primary key etc. The module returns this as a reference using return \%data;

I then do, for example, $records = newfile("text.txt"); to set up the associative array reference, $records is a reference to %data. Then I did @primary = keys(%{$records});. I didn't get quite what I expected.

I was hoping for an array holding all the values that had come from @array[0]. I got them. However, I also got something that looked like 0hashX0f, a hash reference I think, in the first element of the @primary array. Other attempts at fixing it moved the hash reference (?) to other places in the array, seemingly randomly.

Unfortunately the code is at home. Else I'd post it.

Help? Chris $live{$free}||die

Replies are listed 'Best First'.
Re: Odd hash problem.
by Fastolfe (Vicar) on Jan 02, 2001 at 19:24 UTC
    { curley braces } build a hash reference. Your code to "zero" out %data is being treated equivalent to %data = ( {}, undef ). In other words: $data{ {} } = undef. The {} is getting stringifed to HASH(0x...) and its value in %data is undefined. Hashes always start empty, so declaring them with my %hash; or just start using it, and it will be empty as you expect. If you need to clear out a hash, do %hash = (); (parens, denoting an empty list).

    Whenever you see anything strange with you code, your first debugging step should ALWAYS be to run with warnings enabled ('use warnings' or -w flag to Perl), assuming you aren't running with them turned on to begin with. Bonus if your code compiles cleanly with strict turned on too (as it should!). With warnings enabled, you would have seen this:

    Reference found where even-sized list expected at script line n.
      Hmm.. a little more info..

      The reason behind my %data was to localise it to the module. It works without the my, but if I later open another file of data that had the same 'primary keys' it'd overwrite the previous ones. Using my made it local to the particular reference. (Maybe blessing the reference into the package would be a good idea?)

      As for the warnings, its a CGI thing, I'm using CGI qw(fatalsToBrowser);, which doesn't chuck out anything nasty at the moment. I'll check it with the -w option when I get away from the ASP stuff I'm writing in the office. By the way, should have mentioned before, this is Perl on Win32.. don't think it'll make a big difference, but it might.

        If you need to preserve the value of an existing variable only for the duration of a small block, perhaps you want local instead of my. Using 'my' on a variable already declared in the current scope will also generate a warning. Simply localizing its value with local is what you want to do here. This will also set its value to empty within the block you're using it, so a local %hash; is sufficient to get an empty %hash until you leave that block of code, at which point the original value is restored.

        And the CGI::Carp bit is only useful if your application generates its own warnings/errors (including fatal error messages). Add the -w option to Perl (or with 5.6, 'use warnings;') so that Perl will take a look at your code and warn you when things don't look quite right, as it would have in this case.