Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

passing a hash to a sub by reference.. AARRRGGGHHH! 2

Status
Not open for further replies.

MikeLacey

MIS
Nov 9, 1998
13,212
0
0
GB
This code works ok but I don't like it much, inelegant.

use strict;
my %cfg = (
[tab]'oracle_sid' => ''
)

print "oracle_sid=$cfg{'oracle_sid'}\n";
init(\%cfg);
print "oracle_sid=$cfg{'oracle_sid'}\n";

sub init{
[tab]$_[0]{'oracle_sid'} = 'Mike';
}
[/code]
The value of $cfg{'oracle_sid'} is left at 'Mike' after the subroutine call.

But it's not pretty is it... (and, more to the point, not very readable if I have a whole list of parameters)

I'd like to be able to refer to the hash by name, something like this (this doesn't work btw)
Code:
sub init{
my $href = \$_[0];
[tab]$href{'oracle_sid'} = 'Mike';
}
Perldoc perlref sort of implies that you can do this, but stops short of explaining to a mere mortal like myself just how I should do it.

I'd be grateful if someone would point out my glaring misunderstanding B-( (I *hate* not knowing stuff....)
 
Ben, that's great!

If you just do this...

my (@somearray, %somehash);
dosomething("A", "B", \@somearray, \%somehash);

Will @somearray and %somehash be changed after the subroutine? Or would you have to redefine them to point to the output references? It seems to me if you pass a reference in, then it acts on the actual data, not a copy. However, the way Perl does scoping, that doesn't seem to be appropriate either. This is where I get confused X-)
Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
thx Ben,

Looks good.

The &_64;_; thing was a tek-tips bug which looks as if it's been cleared up. It was being displayed instead of @
Mike
michael.j.lacey@ntlworld.com
 
Hi Tom,
Oops, was a late night when I wrote this. Making some typo corrections (in blue) to the "main program" part:

my (@somearray, %somehash);
my ($reftothearray, $reftothehash) = dosomething("A", "B", \@somearray, \%somehash);
my (@passedarray) = @{$reftothearray};
my (%passedhash) = %{$reftothehash};

That will do the trick.
From previous experience with Turbo Pascal I too would've thought that if you pass a pointer you'd act on the actual data (not the copy). You're right--to get any changes to @somearray made inside the subroutine you'd have to redefine it by replacing:
my (@passedarray) = @{$reftothearray};
with:
@somearray = @{$reftothearray};

If you want to cut down on the number of variables used, maybe start with the array as a reference ($somearray) and typecast it (@$somearray):

my ($somearray, %somehash);
@$somearray[0] = "AAAAA";
@$somearray[1] = "BBBBB";
@$somearray[2] = "CCCCC";
foreach $element (@$somearray) {
print "INSIDE MAIN (BEFORE) : $element\n";
}

my ($somearray, $reftothehash) = dosomething("A", "B", $somearray, \%somehash);

foreach $element (@$somearray) {
print "INSIDE MAIN (AFTER) : $element\n";
}

exit;

Sorry for the long post! Is there an easier way?
Take care, :)
Ben
 
I thought I'd add my 2cents - I'm not sure if I'm restating already covered material, but here's a script that shows passing references:

#!/usr/bin/perl -w

use strict;

sub something {
my $ref_scalar_a = shift;
my $ref_array_a = shift;
my $ref_hash_a = shift;

${$ref_scalar_a} = "z"; ### Must dereference the reference
$ref_array_a->[0] = "zzz"; ### Changes the value of the 1st element("a")
### to "zzz".
$ref_hash_a->{'a'} = "xyz"; ### Changes the value of the 1st element
### keyed by "a" to "xyz".
} ### end sub somyething

my $a = "a";
my @array_a = ("a", "b", "c");
my %hash_a = ("a" => "aaa",
"b" => "bbb",
"c" => "ccc");

print "\n";
print &quot;before: scalar \$a = <$a>\n&quot;;
print &quot;before: array \@array_a = &quot; . join(', ', @array_a) . &quot;\n&quot;;
foreach my $key (keys %hash_a) {
print &quot;before: hash key=<$key>, value=<$hash_a{$key}>\n&quot;;
}
something(\$a, \@array_a, \%hash_a);
print &quot;\n&quot;;
print &quot;after : scalar \$a = <$a>\n&quot;;
print &quot;after : array \@array_a = &quot; . join(', ', @array_a) . &quot;\n&quot;;
foreach my $key (keys %hash_a) {
print &quot;after : hash key=<$key>, value=<$hash_a{$key}>\n&quot;;
}

-------------------------------------
Here's the output:

before: scalar $a = <a>
before: array @array_a = a, b, c
before: hash key=<a>, value=<aaa>
before: hash key=<b>, value=<bbb>
before: hash key=<c>, value=<ccc>

after : scalar $a = <z>
after : array @array_a = zzz, b, c
after : hash key=<a>, value=<xyz>
after : hash key=<b>, value=<bbb>
after : hash key=<c>, value=<ccc>
---------------------------------------

The thing to remember is that when you pass a reference to a subroutine, that's exactly what the subroutine receives - a reference. So in the subroutine, if you want to alter the value of what the reference is pointing to, you must use the reference - you can't just use the variable with the same name as the reference - if you passed \$a to a subroutine, then in the subroutine you can't just use $a and expect to see and change the value of what the reference is pointing to - you must dereference the reference by doing ${$a}. If you use the reference properly in the subroutine, then the subroutine doesn't have to pass the reference or the new value back - the calling routine will automatically get an updated variable.

HTH.
Hardy Merrill
Mission Critical Linux, Inc.
 
I know I'm going to have to come back and review this stuff again. In the interests of being able to find it in the future, could one of you write it into a FAQ?
Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
Excellent thread, guys!


keep the rudder amid ship and beware the odd typo
 
Ditto goBoating:

This is an excellent thread! It answers a problem that I have had since December 04/2000. Thanks all!
 
Ditto goBoating:

This is an excellent thread! It answers a problem that I have had since December 04/2000. Now, all I have to do is translate the code to MySQL. Thanks all!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top