Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw

passing hashes and hash reference

by symŽ (Acolyte)
on Apr 20, 2001 at 20:47 UTC ( #74229=perlquestion: print w/replies, xml ) Need Help??
symŽ has asked for the wisdom of the Perl Monks concerning the following question:

I want to pass a hash to a subroutine like:
Then have the routine create a reference to that hash and finally manipulate the referenced hash.
Afterwards, %hash would contain the changes made in myroutine...
Wy won't this work/what will work?
sub myroutine { $hash_ref = \(shift); $$hash_ref{foo}='bar'; }

Replies are listed 'Best First'.
Re: passing hashes and hash reference
by twerq (Deacon) on Apr 20, 2001 at 21:03 UTC
    What you want to do is pass the hash reference to your sub, which expects a reference. Try:

    sub myroutine { $hash_ref = (shift); $$hash_ref{foo}='bar'; } myroutine(\%thishash);

    If you wanted to make sure you were getting a hash reference inside your sub, add a line like this:
    die "Not a HASH reference" unless (ref($hash_ref) eq "HASH");

      "HASH" eq ref($ref) is a fragile test and should be replaced with UNIVERSAL::isa($ref,"HASH").

      Update: The reason the original test is fragile is that it will make your code refuse to work on a hash if it happens to be blessed.

      Update2: Changed "HASH" eq ref to "HASH" eq ref($ref) to avoid confusion. Thanks, BMaximus.

              - tye (but my friends call me "Tye")
        Shouldn't that be: ref($hash) eq "HASH" ?
        Where $hash is a hashref?

        How about a bit more on why the UNIVERSAL::isa() method is better? I'm curious.

        How about:
        sub rref { return UNIVERSAL::isa(@_); } if (rref($hash_ref,'HASH')) { # Wow! It's a hash! }
        UNIVERSAL is such a wacky thing. It's exactly the kind of direction that I would expect Parrot to take, but only if somehow Java were involved.
Re: passing hashes and hash reference
by Masem (Monsignor) on Apr 20, 2001 at 21:04 UTC
    When you pass by value (eg  myroutine( %hash ) ), a copy is made of %hash before it gets to the script so that any changes you do on it will not be seen outside the scope of the subroutine. If you want to change the hash contents, you have to pass the hash by reference:
    my %hash = ( foo => 'baz' ); print $hash{foo}.'\n'; myroutine( \%hash ); print $hash{foo}.'\n'; sub myroutine { my $hash_ref = shift; $$hash_ref{foo}='bar'; }

    Dr. Michael K. Neylon - || "You've left the lens cap of your mind on again, Pinky" - The Brain
Re: passing hashes and hash reference
by slife (Scribe) on Apr 20, 2001 at 21:32 UTC

    To answer the question of why your code snippet won't work, remember that Perl flattens subroutine arguments into a single list of scalars; your code shifts the first element off that list ( a hash key in this case ) and takes a reference to it, i.e. you end up with a reference to a scalar and the remainder of your hash is thrown away.

    Others have posted the correct solution.

Re: passing hashes and hash reference
by stephen (Priest) on Apr 20, 2001 at 21:39 UTC
    You can achieve what you want using subroutine prototypes, so long as you predeclare them. You can learn more on the perlsub manpage. Look at the sections on "Pass By Reference" and "Prototypes".

    When you say

    then %hash is passed to myroutine() as a list. This means that in
    %hash = ( 'alpha' => 'alpher', 'beta' => 'bethe', 'gamma' => 'gamow'); myroutine(%hash); sub myroutine { print shift, "\n"; }
    will print, randomly, either 'alpha', 'beta', or 'gamma'. (In practice, it'll print 'gamma', but in principle the order is undetermined.)


Log In?

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

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (7)
As of 2017-06-28 11:52 GMT
Find Nodes?
    Voting Booth?
    How many monitors do you use while coding?

    Results (632 votes). Check out past polls.