http://qs321.pair.com?node_id=856292

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

Hello,
I have a problem, when I try to use a refernce to an hash in a subroutine.

That works:
sub test { my %q=@_; while ( my ($key, $value) = each(%q) ){ } }

But I need to modify the orginal values, not a copy through "my" .
But that:

sub test { while ( my ($key, $value) = each( {@_} ) ){ #or { $_[0] } with the +same result } }
doesn't work, because I have:
Type of arg 1 to each must be hash (not anonymous hash ({})) near "} +)

Any suggestion about I can solve that?
Thank you!

_____________ UPDATE:

On a suggestion below I write all my code:

I would like to creare a Simply SQL wrapper.
So:
my $dbh; my (%q,@select,@insert,@update,@delete); %q= ( select => \@select, insert =>\@insert, update =>\@update, delete=>\@delete ); $select[0]=['SELECT * FROM emails WHERE `email`=?']; $select[1]=['SELECT * FROM emails AS e RIGHT JOIN bounces AS b ON e.` +emails_id`=b.`emails_id` WHERE e.`email`=? AND b.`email_date`=FROM_UN +IXTIME(?) '];
And then:
sub elabora_st { # argument list: # action='prepare' or action='finish' # then the hash delle query my $action=shift @_; my %q=@_; for my $value (values %q ){ for my $sel ( @$value ) { # print "$sel->[0]\n"; if ( $action eq 'prepare') { # print "$sel->[0] \n"; my $sth=$dbh->prepare($sel->[0]); $sel->[1]=$sth; } elsif ($action eq 'finish') { # to do } } } }
Finally:
&connection; &elabora_st ('prepare',%q); # other stuff # I would like to have queries like that, or something similar: # %q->select[1][1]->execute($address,$mailTime); &end_connection;

But I need to modify the original %q, not a copy...
I think that in object orientend code, I will have a better result, but I'm not yet able to create OO Perl code.
Finally I don't want to modify the global %q, but only the %q passed through argument list.

Replies are listed 'Best First'.
Re: deferencing an hash in a subroutine
by BioLion (Curate) on Aug 20, 2010 at 15:09 UTC

    In neither of your examples are you using a reference. Try something more like:

    use strict; use warnings; my %hash = (foo => 1, bar => 2,); # pass reference to subroutine test(\%hash); ########## SUB ######### sub test{ my $reference = shift; # reference is passed in @_ print "REF: $reference\n"; print "KEY: " . $_ . " VAL: " . $reference->{$_} . "\n" for (keys +%$reference); }

    Check out perlref and References quick reference for more info on references and dereferencing! HTH!

    Just a something something...
Re: deferencing an hash in a subroutine
by moritz (Cardinal) on Aug 20, 2010 at 15:06 UTC
    sub test { for (my $i = 0; $i < @_; $i += 2) { if ($_[$i] eq 'a') { $_[$i+1] = 'found a'; } } } my $a = 'not found'; test b => 3, a => $a; print "$a\n";

    But beware, chaning your caller's arguments is evil, and usually produces code that's hard to understand and read.

    Perl 6 - links to (nearly) everything that is Perl 6.
      and if I try to forse at the end of my sub:
      $_[0]=\%q;

      It will overwrite the previous hash reference. is it correct?
        $_[0]=\%q; sets the first argument on the caller side to \%q. Which only makes sense if you pass a scalar variable as first argument.

        Maybe it would be more helpful if you wrote what the underlying reason is for doing what you try to do. Maybe that way we can suggest a better solution. See also XY Problem.

        Perl 6 - links to (nearly) everything that is Perl 6.
Re: deferencing an hash in a subroutine
by zentara (Archbishop) on Aug 20, 2010 at 15:06 UTC
    Change
    my %q=@_;
    to something that processes @_ into my %q, like
    #!/usr/bin/perl #A quick easy way to do it given @keys (array of keys) and @values #(array of values): #@hash{@keys} = @values; #This will set up the key/value pairs in %hash. #The real pain here is that the files have to be in sync otherwise #the data becomes a mess. #Given the above: my @MyArray1 = qw(5 4 3 2 1 6 9 11 12); my @MyArray2 = qw(cat dog mouse mice tree shrub sap unix max); if ( scalar(@MyArray1) != scalar(@MyArray2) ) { printf "Expecting two equal size arrays, but got the following:\n"; printf "MyArray1: %5d MyArray2: %5d\n"; die "Incorrect data setup"; } my %MyHash = (); while ( scalar(@MyArray1) ) { my $MyKey = pop(@MyArray1); my $MyData = pop(@MyArray2); $MyHash{$MyKey} = $MyData; } foreach my $MyKey (sort {$a <=> $b} keys %MyHash) { printf "%4d: %-s\n", $MyKey, $MyHash{$MyKey}; }

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku
Re: deferencing an hash in a subroutine
by murugu (Curate) on Aug 20, 2010 at 16:36 UTC
    saintex, But in your code you are not using the reference at all. I think if you want to change the original values, Then pass by reference and change it.
    #!/usr/bin/perl -w use strict; my %h = qw(a b c d); &test(\%h); while ( my ($key, $value) = each(%h) ){ print "Key\t $key Value\t $value\n"; } sub test { my $h = shift; $h->{a}= "k"; ..... Some Code ....... }

    Regards,
    Murugesan Kandasamy
    use perl for(;;);

      ok, so I will simply do a call like this:
      &elabora_st ('prepare',\%q);

      Thank yoU!