×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Contact US

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

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

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

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

(OP)
This code works ok but I don't like it much, inelegant.

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

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

sub init{
    $_[0]{'oracle_sid'} = 'Mike';
}

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)

sub init{
my $href = \$_[0];
    $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 (I *hate* not knowing stuff....)

Mike
michael.j.lacey@ntlworld.com
Cargill's Corporate Web Site

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

Mike:-

       I didn't work much in the oracle connectivity.
I think if u need a better code .I can give a try .

give in much simpler way like(please bear with me)

$x= "djhfjhf";
&int($x);
$x="fjgkdg":

sub int()
 {
  fgdfgdfgdf
 }
 
I hope u undrstand what iam expecting



RE: passing a hash to a sub by reference.. AARRRGGGHHH!

(OP)
Thanks for responding thendal

it's nothing to do with oracle to be honest....

I want to be able to pass a hash to subroutine by reference, so that the hash can be modified within the subroutine.

In the example above, the code: (re-written to avoid oracle distractions)

sub init{
    $_[0]{'first_name'} = 'Mike';
}

this code works fine, you call it like this:

my %cfg;
init(\%cfg);

My problem with it is that I don't want to refer to variables inside a subroutine using the $_[0] method... It's ok if you just have the one parameter -- but any more than that and it will become unreadable.

So -- I'd like a way to pass a hash to a subroutine by reference - and then to refer to that hash, within the subroutine, using a readable name rather than by an index into the @_ array.

Mike
michael.j.lacey@ntlworld.com
Cargill's Corporate Web Site

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

I sometimes just pass the hash name.  Like this....


use strict;
$hName = 'cfg';
my %$hName = ( 'oracle_sid' => ' );

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

sub init{
my $hName = $_[0];
$$hName{'oracle_sid'} = 'Mike';
}


I have used this when I needed to handle some unknown number of hashes.  I would keep a list of newly created hash names and then retrieve them as was needed for what ever chore I was working on.  You can just pass the hash name around and dereference the name.  Sorry about using a little different syntax.....' just the way I'm used to playing with references.

hope this helps.




keep the rudder amid ship and beware the odd typo

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

Mike:-

I am new bee.I tried like this.I don't know this is what ur exactly expecting.

%cfg=('firstname' => 'thendal0','firstname2' => 'thendal1');
@array=keys(%cfg);
print "First=$cfg{$array[0]}\n";
$len=scalar @array;
&init($len);
print "First=$cfg{$array[0]}\n";
sub init{
     $len=$_[0];
     for($i=0;$i<$len;$i++)
       {
          $cfg{$i} ="Mike$i";
       }
    }

my whole point is instead of refering each hash values with
$_[0].passing one value(ie,whole length of the array)

I hope this will help u.

Thendal


RE: passing a hash to a sub by reference.. AARRRGGGHHH!

I've done it like this:

my %cfg = ('oracle_sid' => ');

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

sub init
{
  my %cfg = @_;
  $cfg{'oracle_sid'} = 'Mike';
  return %cfg;
}

Only problem is that I've only gotten this to work when the hash is the last parameter in a list and there is only one hash.  I can't pass two hashes this way (which has been a pain in the butt because I had to turn strict off and make a global hash for one of them).

I hope this helps you... and maybe you can solve my problem.

Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
http://www.oac-design.com

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

Please post Mike... what have you found?  Any answers for my problem?

Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
http://www.oac-design.com

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

Wow, UK time must be way off US time ;)

Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
http://www.oac-design.com

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

Does anyone remember Turbo Pascal? (stop retching!)  You could pass whatever into a sub and it would arive intact.  Arrays and all.

Ahhh, those were the days   Maybe in a future version...?

fortytwo
will@hellacool.co.uk
my test site

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

(OP)
I remember Turbo Pascal just fine <grin>
anyway..... as promised, if a little late, sorry about the delay Tom et al..

Initially I wanted to be able to pass a hash to a sub and have a modified version of that hash returned to me by the sub. After some thought (not like me I know) I decided I wanted som checking for programmers who managed to mistype parameter names - so here's what I ended up doing:

config file like this

oracle_sid = pil3
oracle_logon = mlacey/mrbigboy

which is read, in the main program, like this:

use strict;
use Utils;
Utils::init_cfg('bpackar.cfg');
my $orasid=cfg_val('oracle_sid');
my ($orauser, $orapass) = split(/\//,Utils::cfg_val('oracle_logon'),3);

The relevant bit of Utils.pm is this... (You're welcome to all of it, but it's a bit long)

package Utils;
use strict;
my %cfg;
my $cfg_inited = 0;

sub init_cfg($){my ($file)=@_;
my ($config_param, $value);
    die "$0: Utils::init_cfg: no cfg file specified\n" unless $file;
    open(CFGFILE,$file) || die "$0: Utils::init_cfg: cannot open cfg file ile)\n$!\n";
    while(<CFGFILE>){
        chomp;
        s/#.*|^\s+|\s+$//; # remove blank lines, spaces and comments
        next unless length;
        ($config_param, $value) = split(/\s*=\s*/,$_,2);
        Utils::cfg{$config_param}=$value;
    }
    $Utils::cfg_inited = 1;
} # sub init_cfg

sub cfg_val($){my ($key)=@_;

    die "$0: Utils::cfg_val: cfg file not yet read\n" unless $Utils::cfg_inited;
    if(defined($Utils::cfg{$key})){
        return($Utils::cfg{$key});
    } else {
        die "$0: Utils::cfg_val: value ($key) not defined in cfg file\n";
    }
} # sub cfg_val

Mike
michael.j.lacey@ntlworld.com
Cargill's Corporate Web Site
Making mistakes, so you don't have to. <grin>

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

Hi Mike, thanks for posting.  Yeah, Pascal was OK, but not very useful practically.  Mike, I don't see where you are passing a hash to a sub... it looks like your hash is global.  What am I missing?

BTW, I had a new idea for this... make the hash into an object and pass that.

Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
http://www.oac-design.com

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

(OP)
Hi Tom,

Trick is that the hash is defined in the Utils package and only read or written by routines defined within it.

You only get values in the hash by putting them in the cfg file and callng Utils::init_cfg

You only get values out of the hash by calling Utils::cfg_val and if you try and read a value that is not defined in the cfg file it gives you an error message and dies.

Obviously there's nothing to stop a programmer saying something like:

%Utils::cfg{'my_undocumented_param'} = 'yuk';

and then using it, like all Perl stuff really. The idea was to catch errors rather than to enforce a standard.

Perl Objects -- yeah.... I've heard of them but my understanding of them, despite reading the Camel book from cover to cover more than once, is somewhat limited (zero that is). All that blessing gives me a nasty rash... I'm pinning my "Understandable and Readble Perl OO" hopes on Perl6.

Mike
michael.j.lacey@ntlworld.com
Cargill's Corporate Web Site
Making mistakes, so you don't have to. <grin>

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

From what I have heard/read about Perl 6, it seems that it will have a lot of OOP that you can utilize. I read an article by one of the creaters.

I can't wait for 6 to come out too.

-Vic

vic cherubini
malice365@hotmail.com
epic software
====
Knows: Perl, HTML, JavScript, C/C++, PHP, Flash, Director
Wants to Know: Java, Cold Fusion, Tcl/TK
====

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

I don't know how this thread got so complicated, but it seems to me the original question was a less ugly method for using a hash reference in a subroutine. Here's how:

init(\%myhash);

sub init {

my($hashref) = &#64;_;

${$hashref}{'first_name'} = 'Mike';

}


The ${$hashref} part is the trick. It "dereference" $hashref to be a hash, just as if it actually said "myhash", and then the code is interpreted as if it said $myhash{'first_name'}.

Yes, I've read all the perldocs multiple times. Sometimes I STILL have to go back and look up how to use references.

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

(OP)
Thanks for posting tsdragon, much appreciated.

What does &#64;_; do?


Mike
michael.j.lacey@ntlworld.com

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

Hi Mike,
I've been passing hashes and arrays back and forth into and out of subs.  Looks like tsdragon is doing it similar to what I'd suggest below..  I don't know what the &_64;_; is though...

sub dosomething {
   #$getvar1 and $getvar2 are just examples of regular
   #variables being passed; $reftoarray will hold the
   #reference to any array you're passing and same for
   #$reftohash

   my ($getvar1, $getvar2, $reftoarray, $reftohash) = @_;
   my (@array) = @{$reftoarray};
   my (%hash) = %{$reftohash};

   #do whatever here with your hash or array (called %hash
   #and @array, respectively)...

   #pass back out the array and hash references...
   return (\@array, \%hash);
}

#main program

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

exit;

Anyways, hope this is general enough to show everything passing back and forth.  Hope this helps!!

Ben

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

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


Sincerely,
 
Tom Anderson
CEO, Order amid Chaos, Inc.
http://www.oac-design.com

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

(OP)
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

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

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

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

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

-------------------------------------
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.
http://www.missioncriticallinux.com

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

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.
http://www.oac-design.com

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

Excellent thread, guys!


 
 
 keep the rudder amid ship and beware the odd typo

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

Ditto goBoating:

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

RE: passing a hash to a sub by reference.. AARRRGGGHHH!

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!

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members! Already a Member? Login

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close