Array of hashes and strict refs - help!

Discussion in 'Perl Misc' started by Noel Sant, Jan 30, 2004.

  1. Noel Sant

    Noel Sant Guest

    When I run my (test) program below, I get the following error:

    Can't use string ("file") as a HASH ref while "strict refs" in use at
    D:\Houseke
    eping\BackupWithZip\Scripts\hashtest.pl line 28, <INPUT_FILE> line 2.

    The camel book says this means only hard references are allowed by "use
    strict refs", not symbolic ones. But this is more or less what the camel
    book (2nd edition) says to do with arrays of hashes (pp268/9). Why is "file"
    a symbolic ref? Where am I going wrong?

    TIA

    Noel

    # Work out how to use an array of hashes with strict refs
    #
    use strict;

    my $input_line; my $folder; my $file;
    my @array; my %hash;
    my $key; my $i;

    # Lines in test.txt have two strings: a folder name and a file name,
    # separated by spaces
    open INPUT_FILE, "test.txt"
    or die "Can't open test.txt\n";
    while (!eof INPUT_FILE) {
    $folder = "";
    $file = "";
    chomp($input_line = <INPUT_FILE>);
    # Lots of checking of input line for double quotes and spaces,
    # but with a simple line ("aaa bbb") ...
    ($folder, $file) = split (/\s+/, $input_line);
    %hash = (
    folder => $folder,
    file => $file,
    );
    push @array, %hash;
    }
    %hash = ();
    foreach $i (@array) {
    for $key (keys %{$array[$i]}) { # <=== line 28
    print "$key name is $array[$i]{$key}\n";
    }
    }
    close INPUT_FILE;
     
    Noel Sant, Jan 30, 2004
    #1
    1. Advertising

  2. Noel Sant

    Paul Lalli Guest

    On Fri, 30 Jan 2004, Noel Sant wrote:

    > When I run my (test) program below, I get the following error:
    >
    > Can't use string ("file") as a HASH ref while "strict refs" in use at
    > D:\Houseke
    > eping\BackupWithZip\Scripts\hashtest.pl line 28, <INPUT_FILE> line 2.
    >
    > The camel book says this means only hard references are allowed by "use
    > strict refs", not symbolic ones. But this is more or less what the camel
    > book (2nd edition) says to do with arrays of hashes (pp268/9). Why is "file"
    > a symbolic ref? Where am I going wrong?
    >
    > TIA
    >
    > Noel
    >
    > # Work out how to use an array of hashes with strict refs
    > #
    > use strict;
    >
    > my $input_line; my $folder; my $file;
    > my @array; my %hash;
    > my $key; my $i;
    >
    > # Lines in test.txt have two strings: a folder name and a file name,
    > # separated by spaces
    > open INPUT_FILE, "test.txt"
    > or die "Can't open test.txt\n";
    > while (!eof INPUT_FILE) {
    > $folder = "";
    > $file = "";
    > chomp($input_line = <INPUT_FILE>);
    > # Lots of checking of input line for double quotes and spaces,
    > # but with a simple line ("aaa bbb") ...
    > ($folder, $file) = split (/\s+/, $input_line);
    > %hash = (
    > folder => $folder,
    > file => $file,
    > );
    > push @array, %hash;

    ^^^^^
    You can't push a hash into an array. You want to push a reference to that
    hash into the array:
    push @array, \%hash;


    > }
    > %hash = ();
    > foreach $i (@array) {
    > for $key (keys %{$array[$i]}) { # <=== line 28
    > print "$key name is $array[$i]{$key}\n";
    > }
    > }
    > close INPUT_FILE;
    >
    >
    >


    What was happening is that the original hash was getting flattened, adding
    four new elements to the array. One of those elements was the string
    "file", which you then tried to use as a hashref in the foreach loop.

    Paul Lalli
     
    Paul Lalli, Jan 30, 2004
    #2
    1. Advertising

  3. Noel Sant

    Paul Lalli Guest

    On Fri, 30 Jan 2004, Paul Lalli wrote:

    > On Fri, 30 Jan 2004, Noel Sant wrote:
    >
    > > use strict;
    > >
    > > my $input_line; my $folder; my $file;
    > > my @array; my %hash;
    > > my $key; my $i;
    > >
    > > # Lines in test.txt have two strings: a folder name and a file name,
    > > # separated by spaces
    > > open INPUT_FILE, "test.txt"
    > > or die "Can't open test.txt\n";
    > > while (!eof INPUT_FILE) {
    > > $folder = "";
    > > $file = "";
    > > chomp($input_line = <INPUT_FILE>);
    > > # Lots of checking of input line for double quotes and spaces,
    > > # but with a simple line ("aaa bbb") ...
    > > ($folder, $file) = split (/\s+/, $input_line);
    > > %hash = (
    > > folder => $folder,
    > > file => $file,
    > > );
    > > push @array, %hash;

    > ^^^^^
    > You can't push a hash into an array. You want to push a reference to that
    > hash into the array:
    > push @array, \%hash;
    >


    Actually, looking again, you're changing the contents of %hash each time
    through the loop. That's going to cause problems if you keep adding
    references to the same variable. Two solutions - change the scope of my
    %hash to be within the while loop only, or instead push an anonymous hash
    containing the current contents of %hash:
    push @array, { %hash };

    Paul Lalli
     
    Paul Lalli, Jan 30, 2004
    #3
  4. On Fri, 30 Jan 2004 16:43:48 +0000, Noel Sant wrote:

    > When I run my (test) program below, I get the following error:
    >
    > Can't use string ("file") as a HASH ref while "strict refs" in use at
    > D:\Houseke
    > eping\BackupWithZip\Scripts\hashtest.pl line 28, <INPUT_FILE> line 2.
    >
    > The camel book says this means only hard references are allowed by "use
    > strict refs", not symbolic ones. But this is more or less what the camel
    > book (2nd edition) says to do with arrays of hashes (pp268/9). Why is
    > "file" a symbolic ref? Where am I going wrong?
    >
    > TIA
    >
    > Noel
    >
    > # Work out how to use an array of hashes with strict refs #
    > use strict;
    >
    > my $input_line; my $folder; my $file; my @array; my %hash;
    > my $key; my $i;


    You have declared global variables ... read on :)


    > # Lines in test.txt have two strings: a folder name and a file name, #
    > separated by spaces
    > open INPUT_FILE, "test.txt"
    > or die "Can't open test.txt\n";
    > while (!eof INPUT_FILE) {


    Go back and re-read the Camel book. You don't need this. A simple

    while(<INPUT_FILE>) {

    works ;-)

    > $folder = "";
    > $file = "";


    There really isn't a need to do this either. In fact, to make sure the
    variables are empty to begin with, you could do something like ...

    my $folder = "";

    However, when you first declare a variable, it's going to be 'undef'
    anyway, so why bother. Better yet, why not declare the variables within
    the block instead of outside the block. Right now, they're global. There
    really isn't a point in declaring them globally - since they only "live"
    within the block.


    > chomp($input_line = <INPUT_FILE>);
    > # Lots of checking of input line for double quotes and spaces, # but
    > with a simple line ("aaa bbb") ...
    > ($folder, $file) = split (/\s+/, $input_line); %hash = (
    > folder => $folder,
    > file => $file,
    > );
    > push @array, %hash;


    The hash is being flattened. If you want an array of hashes, then use a
    reference to the hash ...

    push @array, \%hash;

    > }
    > %hash = ();


    Now ... why did you do this? During each loop through the the hash, the
    hash values are being replaced. And, again, the life of this variable in
    within the block, so why declare it globally? Declare it at the top of
    the block and each time through the loop, it will get reinitialized.

    > foreach $i (@array) {
    > for $key (keys %{$array[$i]}) { # <=== line 28
    > print "$key name is $array[$i]{$key}\n";
    > }
    > }
    > close INPUT_FILE;


    Just a few general comments. Go back and re-read the Camel book. And
    also read perlstyle (unless you're newsreader butchered your code :) ).
    Review some of the posts here and see examples of what I was talking
    about.

    HTH

    --
    Jim

    Copyright notice: all code written by the author in this post is
    released under the GPL. http://www.gnu.org/licenses/gpl.txt
    for more information.

    a fortune quote ...
    "To YOU I'm an atheist; to God, I'm the Loyal Opposition." --
    Woody Allen
     
    James Willmore, Jan 30, 2004
    #4
  5. Noel Sant

    Ben Morrow Guest

    wrote:
    > On Fri, 30 Jan 2004 16:43:48 +0000, Noel Sant wrote:
    > > ($folder, $file) = split (/\s+/, $input_line); %hash = (
    > > folder => $folder,
    > > file => $file,
    > > );
    > > push @array, %hash;

    >
    > The hash is being flattened. If you want an array of hashes, then use a
    > reference to the hash ...
    >
    > push @array, \%hash;


    Or, perhaps more clearly:

    ($folder, $file) = split ...;
    push @array, {
    folder => $folder,
    file => $file,
    };

    No need for a temporary %hash at all.

    Ben

    --
    The cosmos, at best, is like a rubbish heap scattered at random.
    - Heraclitus
     
    Ben Morrow, Jan 30, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Nagle
    Replies:
    3
    Views:
    312
    John Nagle
    Feb 25, 2007
  2. kazaam
    Replies:
    12
    Views:
    295
    Matthias Wächter
    Sep 13, 2007
  3. Daniel Friedman

    Q: "my" variables and "no strict 'refs'"

    Daniel Friedman, Jun 26, 2003, in forum: Perl Misc
    Replies:
    1
    Views:
    164
    Eric Schwartz
    Jun 26, 2003
  4. Tim O'Donovan

    Hash of hashes, of hashes, of arrays of hashes

    Tim O'Donovan, Oct 27, 2005, in forum: Perl Misc
    Replies:
    5
    Views:
    237
  5. bpatton

    no strict 'refs' need help

    bpatton, Jul 12, 2007, in forum: Perl Misc
    Replies:
    1
    Views:
    146
    Brian McCauley
    Jul 12, 2007
Loading...

Share This Page