Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Accessing HASH pushed into @array ('strict refs' in use error)

by sbrothy (Initiate)
on Jan 08, 2014 at 09:53 UTC ( #1069749=perlquestion: print w/replies, xml ) Need Help??
sbrothy has asked for the wisdom of the Perl Monks concerning the following question:

#! /usr/bin/perl use strict; use warnings; use constant CLIENT_NICK => 'ClientNick'; use constant CLIENT_PATH => 'ClientPath'; my @array; for(my $n = 0; $n < 10; $n++) { my %result = ( CLIENT_NICK => "NICK: $n", CLIENT_PATH => "PATH: $n", ); push @array, %result; } foreach (@array) { print $_->{CLIENT_NICK} . "\n"; print $_->{CLIENT_PATH} . "\n"; }

This results in the error: "Can't use string ("CLIENT_PATH") as a HASH ref while 'strict refs' in use at ./ line 23." Apart from the fact that what I'm 'pushing' into the @array is not a reference (and the curios fact that it complains over CLIENT_PATH before CLIENT_NICK) I'm stumped as to how to get at my data. if I simply

foreach (@array) { print "$_\n"; }

It outputs my data nicely as


(again with the CLIENT_PATH before the CLIENT_NICK). Can someone explain this to me and tell me how I get at my data in an orderly fashion along the lines of the first example, please? TIA /Soren

Replies are listed 'Best First'.
Re: Accessing HASH pushed into @array ('strict refs' in use error)
by dave_the_m (Prior) on Jan 08, 2014 at 10:07 UTC
    That should be (note the backslash):
    push @array, \%result;


      Thanks for your input. But I'm not really interested in sending back references to hashes am I? Won't they go out of scope when I enter the next 'for' run?

        No! Perl uses reference counting, so an element of storage is eligible for garbage collection only when its reference count falls to zero. When you create the %result variable with my, its reference count is one. When you create a reference to it and push that reference onto @array, the reference count of the memory holding the data is incremented to 2. Then, when the for loop is exited iterates, the lexical variable %hash does indeed go out of scope, so the reference count of the memory it is using is decremented back to 1. But it’s still greater than 0, so the data won’t be garbage collected.

        This is one of the features of Perl that make it a joy to work with. As a general rule, Perl is designed to “do the right thing”, which in this case means keeping the data around as long as it’s needed. Reference counting ensures that the data is still valid and available when it is later accessed via the @array variable.

        But — try it to see!

        Hope that helps,

        Update 1: Improved wording slightly.
        Update 2: Added link.
        Update 3: s/is exited/iterates/.

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        Think of my as another language's new: It dynamically creates a variable. (This isn't quite true, but it is the idea behind my, and a good way of thinking of it.)
Re: Accessing HASH pushed into @array ('strict refs' in use error)
by kcott (Chancellor) on Jan 08, 2014 at 10:09 UTC

    G'day sbrothy,

    Welcome to the monastery.

    There's a number of places in your code where you are making constants look like strings due to the surrounding code.

    This is all explained in "constant: CAVEATS" with examples of how to fix "$hash{CONSTANT}" and "CONSTANT => 'value'".

    -- Ken

      Thanks. Again the constants was a leftover from my C days. I removed them all and lo and behold it runs just as nice without them. :)
Re: Accessing HASH pushed into @array ('strict refs' in use error)
by Athanasius (Chancellor) on Jan 08, 2014 at 10:45 UTC

    Hello sbrothy, and welcome to the Monastery!

    To expand on dave_the_m’s answer:

    Step 4 of the Basic debugging checklist says: “Dump arrays, hashes and arbitrarily complex data structures.” Using the core Data::Dumper module to print out the contents of @array, we see that after the first push the array contains 4 elements, which Data::Dumper names $VAR1 to $VAR4:

    $VAR1 = 'CLIENT_PATH'; $VAR2 = 'PATH: 0'; $VAR3 = 'CLIENT_NICK'; $VAR4 = 'NICK: 0';

    That’s because push puts its argument(s) (following the destination array) into list context, and a hash in list context returns a list of the form (key-x, val-x, key-y, val-y, ...). But when a reference to the hash is pushed instead, the result of the first push is:

    $VAR1 = { 'CLIENT_PATH' => 'PATH: 0', 'CLIENT_NICK' => 'NICK: 0' };

    — which shows that only one element ($VAR1) has been pushed onto the array; and this time its referent retains its identity as a hash.

    Some useful reading: perlreftut and perldsc.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Yes. I've taken Data::Dumper to my chest. Thanks for the tip. I'm still looking for a decent TRACE module. Something along the lines og ASSERT and TRACE from Visual C++. I'm trying out Smart::Comments but I dunno...
Re: Accessing HASH pushed into @array ('strict refs' in use error)
by choroba (Chancellor) on Jan 08, 2014 at 13:19 UTC
    Also, you are not using the constants in the code. The fat comma (=>) quotes its left side if it is a valid identifier string, the same applies to hash keys in curlies. Use &CLIENT_NICK or CLIENT_NICK() to disambiguate.
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1069749]
Approved by marto
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (8)
As of 2017-05-22 23:24 GMT
Find Nodes?
    Voting Booth?