When I use the arguments in the function, $file should be $_[0] but how can I use the %hash argument if I want to do something like $hash{$something}++ ? It seems like $_[1]{$something}++ is wrong. What is the right way to use the %hash it is pass into the function as an argument?

If you are passing different bits of data to a function, and you want the data to remain seperate, you use references and dereferencing. If you try and pass multiple lists (hashes or arrays) to a function or sub routine the lists are flattened, they become one long list. Here is an example of passing a scalar and a hash to a sub routine:

Thanks for the info. If I want to pass the hash to a function and make some changes to the original hash table, is that possible? I do not want to use globle variable, so I want to pass the hash table into the function. But if I make changes of the has inside the function, it will not change the original hash right? How do I solve that problem?

Thanks for the info. If I want to pass the hash to a function and make some changes to the original hash table, is that possible? I do not want to use globle variable, so I want to pass the hash table into the function. But if I make changes of the has inside the function, it will not change the original hash right? How do I solve that problem?

Any changes you make to the hash in the function will change the original hash. The reference to the hash points to the address of the original hash. The reference is not passing a copy of the hash.

As far as I know its the same even if you are not using reference. Any data passed in the system array is the actual data, not copies of the data. -------------------------------------------------

If I want to pass the hash to a function and make some changes to the original hash table, is that possible? I do not want to use globle variable, so I want to pass the hash table into the function. But if I make changes of the has inside the function, it will not change the original hash right? How do I solve that problem?

When using something like

Code

function(%hash);

sub function { my %hash = @_;

... }

Then the version of %hash within the function only contains a copy of the values in your original hash. And changes you make will be lost when you leave the function.

You have two options, depending on how complex your requirements are.

1/ You can return the updated hash from the function. This is by far the easiest solution.

Code

%hash = function(%hash);

sub function { my %hash = @_;

# do stuff

return %hash; }

2/ You can pass a reference to the hash into the subroutine.

Code

function(\%hash);

sub function { my $hash_ref = shift;

my %hash = %$hash_ref;

# now, any changes you make to %hash will be reflected # outside of the function }

Any changes you make to the hash in the function will change the original hash. The reference to the hash points to the address of the original hash. The reference is not passing a copy of the hash.

As far as I know its the same even if you are not using reference. Any data passed in the system array is the actual data, not copies of the data.

Is there a difference between using a reference and not using a reference when passing data to a sub as far as affecting the original list, be it array or hash or even scalars? -------------------------------------------------

The scalars in @_ are implicit aliases for the ones passed in, not copies. That means changing the elements of @_ in a subroutine changes the values in the subroutine's caller. This is a holdover from before Perl had proper references.

So, we can write functions that leave their arguments intact, by copying the arguments to private variables like this:

The scalars in @_ are implicit aliases for the ones passed in, not copies. That means changing the elements of @_ in a subroutine changes the values in the subroutine's caller. This is a holdover from before Perl had proper references.

So, we can write functions that leave their arguments intact, by copying the arguments to private variables like this:

That's absolutely right. And nothing has changed there since the first edition of the cookbook.

However. Whilst this is easy to deal with when your argument is a list of scalars or an array, it's not as easy if it's a hash. Look at this...

Code

my %hash = (1 => 100, 2 => 200, 3 => 300);

Now here we've initialised a hash from a list. That's, of course, the standard way to create a hash in Perl.

But what happens when we flatten that hash back into a list in order to print it out.

Code

print join ' ', %hash;

On my computer, that prints out:

1 100 3 300 2 200

On you computer it could well print something different as you can't guarantee the order that a hash is stored in.

When you pass that hash into your subroutine, the hash is flattened into a list which is then stored in the array @_.

So there you are in your subroutine with a "flattened" hash in @_. You know that alternate elements of @_ contain the keys an values from the hash, but there is no way to know what order they are in. Which makes it really hard to alter specific values in the hash.

My first demo function (double) demostrated this approach. As you can't know which order the hash is in, you can't alter specific values, but you _can_ alter all of the values by iterating across the whole of the array. I have to admit that I was slightly surprised that only the values were updated and not the keys. I need to investigate why that works like that.

And then I had an idea. We can't know what order the keys are in when stored in @_, but that doesn't matter if we copy the data into another hash. But, of course, when we copy the data into a hash and change that hash, then we're no longer updating @_ and we're back to the situation where we loose the changes once we leave the subroutine. But (I found myself thinking) what happens if we copy the altered hash back into @_ at the end of the subroutine.

So I tried it (see "double2"). And it seems to work. But I can't ever recall seeing anyone else recommend this method. So I suspect there may be a good reason for not using it. I'll investigate further, but in the meantime I can't reall recommend you using it.

You should probably just stick with either returning the altered hash from the subroutine or passing a reference in as I discussed earlier.

I'm not sure I've been particularly clear here. I'm still trying to work this stuff out in my own head.

So if we are using the passing reference way to do it, do we really have to use $hash_ref = shift?

You should be using strict, in which case the answer is yes. If you are not using strict then all your variables are global and you can access them without passing data in the system array to functions and there is no need to use a reference. -------------------------------------------------