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

Hello Monks,

I just learned how to use References, but I am still confused. Currently, I try to write a script that reads a txt file that has 5 columns, each separated by some whitespace. Each Row corresponds to a gene and the columns are the 1. Gene identifyer 2. sequence 3. sequence length 4. GC content 5. CAI. It's not important what that is.

I want to store the individual attributes into a hash with the identifyer as keys, and a reference to an array containing the remaining attributes as the values. When I try to print the hash, perl complains about my infix operator, except when I write the % symbol instead of the $ symbol. But I learned it the other way. In addition, Perl complains that hash references are deprecated. I'm confused.

Here's my code:
my $file = 'data.txt'; open READ, $file || die "Cannot open $file: $!\n"; my %hash; while (<READ>){ chomp; my ($id, $seq, $length, $gc, $cai) = split /\s+/, $_; $hash{$id} = [ $seq, $length, $gc, $cai ]; } close (READ); foreach (keys %hash){ print $_, "\t", %hash->{$_}[1], "\t", %hash->{$_}[2], "\n"; }

this code only leads to the warning: Using a hash as a reference is deprecated! When I change the last line to  print $_, "\t", $hash->{$_}[1], ... it also complains: Global symbol $hash requires explicit ...

Can anyone clarify the situation? Thanks in advance!

Replies are listed 'Best First'.
Re: references - proper use of infix (arrow) and deprecated hash references
by Theodore (Hermit) on Jul 18, 2017 at 08:47 UTC
    Hi. %hash is not a a hash reference, is a hash. Check the following:
    # This is a hash: my %hash = ( 1 => 'one', 2 => 'two', ); # This is a hash ref: my $hashref = { 1 => 'one', 2 => 'two', }; # This is a hash ref of the hash above: my $hashref2 = \%hash; # Get a hash value: print "Hash: " . $hash{1} . "\n"; # Get a hashref value: print "Hash ref: " . $hashref->{1} . "\n";
    Edited: Also just noted that the values of your hash are array references, so the print line should be:
    print $_, "\t", $hash{$_}->[1], "\t", $hash{$_}->[2], "\n";
Re: references - proper use of infix (arrow) and deprecated hash references
by dsheroh (Monsignor) on Jul 18, 2017 at 09:04 UTC
    In short, you appear to have confused a hash reference (i.e., a reference to a hash) with a hash containing references. What you have here in the posted code is just a plain ol' hash (%hash) which holds a number of array references ([ ... ]).

    To fix the last line, you need to treat the hash as a hash instead of trying to use it as a reference - change %hash->{$_}[1] to $hash{$_}[1] (and the same for [2]) and you should be good to go.

    As for the error messages:

    Using a hash as a reference is deprecated: You get this because you're trying to use an actual hash (not a hash reference) as if it were a reference. This used to be allowed, but isn't any more.

    Global symbol "$hash" requires explicit package name: This one comes from trying to dereference the variable $hash, which doesn't exist. In Perl 5, %hash refers to the hash as a whole and $hash{x} refers to a single item within %hash, while $hash (with no {}) is an independent scalar. The sigil represents the part of the variable you're accessing, not the variable itself. (Note that this is different in Perl 6, where anything related to %hash is always accessed using the % sigil.)

    Edit: Corrected typo. Had a %_ where it should have been $_.

      Note that $hash{%_}[1] should be $hash{$_}[1] instead.

        Thanks! I've corrected the typo in my original reply.
Re: references - proper use of infix (arrow) and deprecated hash references
by haukex (Archbishop) on Jul 18, 2017 at 09:47 UTC

    In addition to what the others have already said, some good links might be perlreftut and perldsc (the latter contains a section "hashes of arrays" which is what you've got).

    I just wanted to add a few more notes: You should always Use strict and warnings as this will help avoid some errors. Also, open READ, $file || die is probably not what you want: it is interpreted as open(READ, ($file || die())); (that is, throw an error when $file has a false value) instead of open(READ, $file) || die; (throw an error when open returns a false value). The reason is that || has a higher precedence (perlop). It's common to use the lower-precedence or instead, i.e. open READ, $file or die, which will work correctly. Also, nowadays lexical filehandles and the three-argument form of open are recommended, that is open my $readfh, '<', $file or die ...; Lastly, note that keys will return the keys of the hash in a random order, so if you used foreach (sort keys %hash), they'd be returned in a consistent order across runs of the program.

Re: references - proper use of infix (arrow) and deprecated hash references
by AnomalousMonk (Archbishop) on Jul 18, 2017 at 12:53 UTC
    ... perl complains about my infix operator, except when I write the % symbol instead of the $ symbol. But I learned it the other way.

    As others have noted, an expression like  %hash->{whatever} is deprecated since many winters, kemosabe. Just as a matter of idle curiosity, I'd be interested to learn who taught you this syntax :)


    Give a man a fish:  <%-{-{-{-<