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

Hi Monks, I am trying to get a simple subroutine to work, whereby I am passing it two hashes by reference and returning two arrays by reference. Anyway, its not behaving as I hoped and I wondered if anyone could explain to me why/ give me a few pointers!? Cheers.
#The code not working my ($common_ref, $total_ref) = calc_enthalpy (\%hash, \%enthalpy_hash) +; @total = @$total_ref; @common = @$common_ref; print "TEST: @total @common<P>"; sub calc_enthalpy { my ($hash, $enthalpy_hash) = @_; my (@common, @total); foreach (keys %enthalpy_hash) { if (exists $hash{$_}) { push @common, "$_ = ", $ +enthalpy_hash{$_} * $hash{$_}, "\n"; push @total, $enthalpy_h +ash{$_} * $hash{$_}, "\n"; } return (\@common, \@total); } }
The next snippet is the code working perfectly not in a sub-routine.
foreach (keys %enthalpy_hash) { if (exists $hash{$_}) { push @common, "$_ = ", $enthalpy_hash{$_} * $hash{$_}, + "\n"; push @total, $enthalpy_hash{$_} * $hash{$_}, "\n"; } # etc }

Replies are listed 'Best First'.
Re: subroutines - passing hashes by reference
by perlplexer (Hermit) on May 01, 2003 at 15:12 UTC
    Not using strict, eh?
    If you did, Perl would compain right here:
    foreach (keys %enthalpy_hash) { ...
    and here
    if (exists $hash{$_}) { ...
    Since you're passing hash refs, you need to treat them accordingly;i.e,
    foreach (keys %$enthalpy_hash) { ...
    and
    if (exists $hash->{$_}) { ...
    Those are just a couple of examples, of course. There's a few other places where you used hash refs improperly.

    Time to read perlref. :)

    --perlplexer
      Hi, thanks for your advice but I am using strict! Is this any better?? It atill doesn't work right ;-(
      sub calc_enthalpy { my ($hash, $enthalpy_hash) = @_; my (@common, @total); foreach (keys %$enthalpy_hash) { if (exists $hash->{$_}) { push @common, "$_ = ", $ +enthalpy_hash->{$_} * $hash->{$_}, "\n"; push @total, $enthalpy_h +ash->{$_} * $hash->{$_}, "\n"; } return (\@common, \@total); } }
        OK, then Perl doesn't complain because you have global variables with the same names.
        Please see other comments as well. Your return() is most likely misplaced.

        --perlplexer
Re: subroutines - passing hashes by reference
by broquaint (Abbot) on May 01, 2003 at 15:14 UTC
    Aha, your problem there is that you are treating a scalar has reference as a hash, however they are two distinct things. What you need to be doing is dereferencing your hash reference when using it e.g
    foreach (keys %$enthalpy_hash) { if(exists $hash->{$_}) { push @common, "$_ = ", $enthalpy_hash->{$_} * $hash->{$_}, "\n"; push @total, $enthalpy_hash->{$_} * $hash->{$_}, "\n"; } }
    See. tye's References quick reference and the venerable perlref for more info on references and dereferencing in perl. On a side note the likes of strict will catch this sort of error upon a simple perl -c.
    HTH

    _________
    broquaint

Re: subroutines - passing hashes by reference
by jasonk (Parson) on May 01, 2003 at 15:14 UTC

    That return(\@common, \@total) probably needs to be closer to the end of the subroutine, the way you have it written now, you are returning after checking only one of the keys of %enthalpy_hash.


    We're not surrounded, we're in a target-rich environment!
Re: subroutines - passing hashes by reference
by Mr. Muskrat (Canon) on May 01, 2003 at 15:18 UTC

    In addition to what perlplexer said, try moving your return outside the foreach loop :-)

    What happened? I thought I wrote this right after perlplexer posted his reply. /me shrugs.

      many many thanks - moved the return and its perfect!
        A side note - really just a personal preference of mine that might help you. Name variables what they are - if a scalar is a reference to a hash, name it as such. For example, if you pass a reference to a 'user' hash in to subroutine print_user, then do it this way:
        sub print_user { my $user_hashref = shift; print "user name = $user_hashref->{'name'}\n"; print "user age = $user_hashref->{'age'}\n"; } ### main part of code ### my %user = { "name" => "John Doe", "age" => 12 } print_user(\%user);
        That way, you always know that scalar $user_hashref is really just a *reference* to the user hash, and it needs to be treated like a reference to a hash, instead of like an actual hash.

        HTH.