Deferencing hash of hashes in Perl - perl

Sorry for this long post, the code should be easy to understand for veterans of Perl. I'm new to Perl and I'm trying to figure out this bit of code:
my %regression;
print "Reading regression dir: $opt_dir\n";
foreach my $f ( glob("$opt_dir/*.regress") ) {
my $name = ( fileparse( $f, '\.regress' ) )[0];
$regression{$name}{file} = $f;
say "file $regression{$name}{file}";
say "regression name $regression{$name}";
say "regression name ${regression}{$name}";
&read_regress_file( $f, $regression{$name} );
}
sub read_regress_file {
say "args #_";
my $file = shift;
my $href = shift;
say "href $href";
open FILE, $file or die "Cannot open $file: $!\n";
while ( <FILE> ) {
next if /^\s*\#/ or /^\s*$/;
chomp;
my #tokens = split "=";
my $key = shift #tokens;
$$href{$key} = join( "=", #tokens );
}
close FILE;
}
The say lines are things I added to debug.
My confusion is the last part of the subroutine read_regress_file. It looks like href is a reference from the line my $href = shift;. However, I'm trying to figure out how the hash that was passed got referenced in the first place.
%regression is a hash with keys of $name. The .regress files the code reads are simple files contains variables and their values in the form of:
var1=value
var2=value
...
So it looks like the line
my $name = (fileparse($f,'\.regress'))[0];
is creating the keys as scalars and the line
$regression{$name}{file} = $f;
actually makes $name into a hash.
In my debugging lines
say "regression name $regression{$name}";
prints the reference, for instance
regression name HASH(0x7cd198)
but
say "regression name ${regression}{$name}";
prints a name, like
regression name {filename}
with the file name inside the braces.
However, using
say "regression name $$regression{$name}";
prints nothing.
From my understanding, it looks like regression is an actual hash, but the references are the nested hashes, name.
Why does my deference test line using braces work, but the other form of dereferencing ($$) not work?
Also, why is the name still surrounded by braces when it prints? Shouldn't I be dereferencing $name instead?
I'm sorry if this is difficult to read. I'm confused which hash is actually referenced, and how to deference them if the reference is the nested hash.

This is a tough one. You've found some very awkward code that displays what may well be a bug in Perl, and you're getting confused over dereferencing Perl data structures. Standard Perl installations include the full set of documentation, and I suggest you take a look at perldoc perlreftut which is also available online at perldoc.com
The most obvious thing is that you are writing very old-fashioned Perl. Using an ampersand & to call a Perl subroutine hasn't been considered good practice since v5.8 was released fourteen years ago
I don't think there's much need to go beyond your clearly experimentatal lines at the start of the first for loop. Once you have understood this the rest should follow
say "file $regression{$name}{file}";
say "regression name $regression{$name}";
say "regression name ${regression}{$name}";
First of all, expanding data structure references within a string is unreliable. Perl tries to do what you mean, but it's very easy to write something ambiguous without realising it. It is often much better to use printf so that you can specify the embedded value separately. For instance
printf "file %s\n", $regression{$name}{file};
That said, you have a problem. $regression{$name} accesses the element of hash %regression whose key is equal to $name. That value is a reference to another hash, so the line
say "regression name $regression{$name}";
prints something like
regression name HASH(0x29348b0)
which you really don't want to see
Your first try $regression{$name}{file} accesses the element of the secondary hash that has the key file. That works fine
But ${regression}{$name} should be the same as $regression{$name}. Outside a string it is, but inside it's like ${regression} and {$name} are treated separately
There are really too many issues here for me to start guessing where you're stuck, especially without being able to talk about specifics. But it may help if I rewrite the initial code like this
my %regression;
print "Reading regression dir: $opt_dir\n";
foreach my $f ( glob("$opt_dir/*.pl") ) {
my ($name, $path, $suffix) = fileparse($f, '\.regress');
$regression{$name}{file} = $f;
my $file_details = $regression{$name};
say "file $file_details->{file}";
read_regress_file($f, $file_details);
}
I've copied the hash reference to $file_details and passed it to the subroutine like that. Can you see that each element of %regression is keyed by the name of the file, and that each value is a reference to another hash that contains the values filled in by read_regress_file?
I hope this helps. This isn't really a forum for teaching language basics so I don't think I can do much better

What I understand is that this:
$regression{$name}
represents a hashref, which looks like this:
{ file => '...something...'}
So, in order to dereference the hashref returned by $regression{$name}, you have to do something like:
%{ $regression{$name} }
In order to get the full hash.
In order to get the file property of the hash, do this:
$regression{$name}->{file}
Hope this helps.

Related

what does print for mean in Perl?

I need to edit some Perl script and I'm new to this language.
I encountered the following statement:
print for (#$result);
I know that $result is a reference to an array and #$result returns the whole array.
But what does print for mean?
Thank you in advance.
In Perl, there's such a thing as an implicit variable. You may have seen it already as $_. There's a lot of built in functions in perl that will work on $_ by default.
$_ is set in a variety of places, such as loops. So you can do:
while ( <$filehandle> ) {
chomp;
tr/A-Z/a-z/;
s/oldword/newword/;
print;
}
Each of these lines is using $_ and modifying it as it goes. Your for loop is doing the same - each iteration of the loop sets $_ to the current value and print is then doing that by default.
I would point out though - whilst useful and clever, it's also a really good way to make confusing and inscrutable code. In nested loops, for example, it can be quite unclear what's actually going on with $_.
So I'd typically:
avoid writing it explicitly - if you need to do that, you should consider actually naming your variable properly.
only use it in places where it makes it clearer what's going on. As a rule of thumb - if you use it more than twice, you should probably use a named variable instead.
I find it particularly useful if iterating on a file handle. E.g.:
while ( <$filehandle> ) {
next unless m/keyword/; #skips any line without 'keyword' in it.
my ( $wiggle, $wobble, $fronk ) = split ( /:/ ); #split $_ into 3 variables on ':'
print $wobble, "\n";
}
It would be redundant to assign a variable name to capture a line from <$filehandle>, only to immediately discard it - thus instead we use split which by default uses $_ to extract 3 values.
If it's hard to figure out what's going on, then one of the more useful ways is to use perl -MO=Deparse which'll re-print the 'parsed' version of the script. So in the example you give:
foreach $_ (#$result) {
print $_;
}
It is equivalent to for (#$result) { print; }, which is equivalent to for (#$result) { print $_; }. $_ refers to the current element.

Pass by value vs pass by reference for a Perl hash

I'm using a subroutine to make a few different hash maps. I'm currently passing the hashmap by reference, but this conflicts when doing it multiple times. Should I be passing the hash by value or passing the hash reference?
use strict;
use warnings;
sub fromFile($){
local $/;
local our %counts =();
my $string = <$_[0]>;
open FILE, $string or die $!;
my $contents = <FILE>;
close FILE or die $!;
my $pa = qr{
( \pL {2} )
(?{
if(exists $counts{lc($^N)}){
$counts{lc($^N)} = $counts{lc($^N)} + 1;
}
else{
$counts{lc($^N)} = '1';
}
})
(*FAIL)
}x;
$contents =~ $pa;
return %counts;
}
sub main(){
my %english_map = &fromFile("english.txt");
#my %german_map = &fromFile("german.txt");
}
main();
When I run the different txt files individually I get no problems, but with both I get some conflicts.
Three comments:
Don't confuse passing a reference with passing by reference
Passing a reference is passing a scalar containing a reference (a type of value).
The compiler passes an argument by reference when it passes the argument without making a copy.
The compiler passes an argument by value when it passes a copy of the argument.
Arguments are always passed by reference in Perl
Modifying a function's parameters (the elements of #_) will change the corresponding variable in the caller. That's one of the reason the convention to copy the parameters exists.
my ($x, $y) = #_; # This copies the args.
Of course, the primary reason for copying the parameters is to "name" them, but it saves us from some nasty surprises we'd get by using the elements of #_ directly.
$ perl -E'sub f { my ($x) = #_; "b"=~/(.)/; say $x; } "a"=~/(.)/; f($1)'
a
$ perl -E'sub f { "b"=~/(.)/; say $_[0]; } "a"=~/(.)/; f($1)'
b
One cannot pass an array or hash as an argument in Perl
The only thing that can be passed to a Perl sub is a list of scalars. (It's also the only thing that can be returned by one.)
Since #a evaluates to $a[0], $a[1], ... in list context,
foo(#a)
is the same as
foo($a[0], $a[1], ...)
That's why we create a reference to the array or hash we want to pass to a sub and pass the reference.
If we didn't, the array or hash would be evaluated into a list of scalars, and it would have to be reconstructed inside the sub. Not only is that expensive, it's impossible in cases like
foo(#a, #b)
because foo has no way to know how many arguments were returned by #a and how many were returned by #b.
Note that it's possible to make it look like an array or hash is being passed as an argument using prototypes, but the prototype just causes a reference to the array/hash to be created automatically, and that's what actually passed to the sub.
For a couple of reasons you should use pass-by-reference, but the code you show returns the hash by value.
You should use my rather than local except for built-in variables like $/, and then for only as small a scope as possible.
Prototypes on subroutines are almost never a good idea. They do something very specific, and if you don't know what that is you shouldn't use them.
Calling subroutines using the ampersand sigil, as in &fromFile("english.txt"), hasn't been correct since Perl 4, about twenty years ago. It affects the parameters delivered to a subroutine in at least two different ways and is a bad idea.
I'm not sure why you are using a file glob with my $string = <$_[0]>. Are you expecting wildcards in the filename passed as the parameter? If so then you will be opening and reading only the first matching file, otherwise the glob is unnecessary.
Lexical file handles like $fh are better than bareword file handles like FILE, and will be closed implicitly when they are destroyed - usually at the end of the block where they are declared.
I am not sure how your hash %counts gets populated. No regex on its own can fill a hash, but I will have to trust you!
Try this version. People familiar with Perl will thank you (ironically!) for not using camel-case variable names. And it is rare to see a main subroutine declared and called. That is C, this is Perl.
Update I have changed this code to do what your original regex did.
use strict;
use warnings;
sub from_file {
my ($filename) = #_;
my $contents = do {
open my $fh, '<', $filename or die qq{Unable to open "$filename": $!};
local $/;
my $contents = <$fh>;
};
my %counts;
$counts{lc $1}++ while $contents =~ /(?=(\pL{2}))/g;
return \%counts;
}
sub main {
my $english_map = from_file('english.txt');
my $german_map = from_file('german.txt');
}
main();
You can use either a reference or pass the entire hash or array. Your choice. There are two issues that might make you choose one over the other:
Passing other parameters
Memory Management
Perl doesn't really have subroutine parameters. Instead, you're simply passing in an array of parameters. What if you're subroutine is seeing which array has more elements. I couldn't do this:
foo(#first, #second);
because all I'll be passing in is one big array that combines all the members of both. This is true with hashes too. Imagine a program that takes two hashes and finds the ones with common keys:
#common_keys = common(%hash1, %hash1);
Again, I'm combining all the keys and their values in both hashes into one big array.
The only way around this issue is to pass a reference:
foo(\#first, \#second);
#common_keys = common(\%hash1, \%hash2);
In this case, I'm passing the memory location where these two hashes are stored in memory. My subroutine can use those hash references. However, you do have to take some care which I'll explain with the second explanation.
The second reason to pass a reference is memory management. If my array or hash is a few dozen entries, it really doesn't matter all that much. However, imagine I have 10,000,000 entries in my hash or array. Copying all those members could take quite a bit of time. Passing by reference saves me memory, but with a terrible cost. Most of the time, I'm using subroutines as a way of not affecting my main program. This is why subroutines are suppose to use their own variables and why you're taught in most programming courses about variable scope.
However, when I pass a reference, I'm breaking that scope. Here's a simple program that doesn't pass a reference.
#! /usr/bin/env perl
use strict;
use warnings;
my #array = qw(this that the other);
foo (#array);
print join ( ":", #array ) . "\n";
sub foo {
my #foo_array = #_;
$foo_array[1] = "FOO";
}
Note that the subroutine foo1 is changing the second element of the passed in array. However, even though I pass in #array into foo, the subroutine doesn't change the value of #array. That's because the subroutine is working on a copy (created by my #foo_array = #_;). Once the subroutine exists, the copy disappears.
When I execute this program, I get:
this:that:the:other
Now, here's the same program, except I'm passing in a reference, and in the interest of memory management, I use that reference:
#! /usr/bin/env perl
use strict;
use warnings;
my #array = qw(this that the other);
foo (\#array);
print join ( ":", #array ) . "\n";
sub foo {
my $foo_array_ref = shift;
$foo_array_ref->[1] = "FOO";
}
When I execute this program, I get:
this:FOO:the:other
That's because I don't pass in the array, but a reference to that array. It's the same memory location that holds #array. Thus, changing the reference in my subroutine causes it to be changed in my main program. Most of the time, you do not want to do this.
You can get around this by passing in a reference, then copying that reference to an array. For example, if I had done this:
sub foo {
my #foo_array = #{ shift() };
I would be making a copy of my reference to another array. It protects my variables, but it does mean I'm copying my array over to another object which takes time and memory. Back in the 1980s when I first was programming, this was a big issue. However, in this age of gigabyte memory and quadcore processors, the main issue isn't memory management, but maintainability. Even if your array or hash contained 10 million entries, you'll probably not notice any time or memory issues.
This also works the other way around too. I could return from my subroutine a reference to a hash or the entire hash. Many people like returning a reference, but this could be problematic.
In object oriented Perl programming, I use references to keep track of my objects. Normally, I'll have a reference to a hash I can use to store other values, arrays, and hashes.
In a recent program, I was counting IDs and how many times they are referenced in a log file. This was stored in an object (which is just a reference to a hash). I had a method that would return the entire hash of IDs and their counts. I could have done this:
return $self->{COUNT_HASH};
But, what happened, if the user started modifying that reference I passed? They would be actually manipulating my object without using my methods to add and subtract from the IDs. Not something that I want them to do. Instead, I create a new hash, and then return a reference to that hash:
my %hash_counts = % { $self-{COUNT_HASH} };
return \%hash_count;
This copied my reference to an array, and then I passed the reference to the array. This protects my data from outside manipulation. I could still return a reference, but the user would no longer have access to my object without going through my methods.
By the way, I like using wantarray which gives the caller a choice on how they want their data:
my %hash_counts = %{ $self->{COUNT_HASH} };
return want array ? %hash_counts : \%hash_counts;
This allows me to return a reference or a hash depending how the user called my object:
my %hash_counts = $object->totals(); # Returns a hash
my $hash_counts_ref = $object->totals(); # Returns a reference to a hash
1 A footnote: The #_ array is pointing to the same memory location as the parameters of your calling subroutine. Thus, if I pass in foo(#array) and then did $_[1] = "foo";, I would be changing the second element of #array.

How to change an array into a hashtable?

I'm trying to make a program where I read in a file with a bunch of text in it. I then take punctuation out and then I read in a file that has stop words in it. Both get read in and put into arrays. I'm trying to put the array of the general text file and put it in a hash. I'm not really sure what I'm doing wrong, but I'm trying. I want to do this so I can generate stats on how many words are repeated and what not, but I have to take out stop words and such.
Anyway here is what I have so far I put a comment #WORKING ON MERGING ARRAY INTO HASH that is where I'm working at. I don't think the way I'm trying to put the array into the hash is right, but I looked online and the %hash{array} = "value"; doesn't compile. so not sure how else to do it.
Thanks, if you have any questions for me I will respond back quickly.
#!/usr/bin/perl
use strict;
use warnings;
#Reading in the text file
my $file0="data.txt";
open(my $filehandle0,'<', $file0) || die "Could not open $file0\n";
my#words;
while (my $line = <$filehandle0>){
chomp $line;
my #word = split(/\s+/, $line);
push(#words, #word);
}
for (#words) {
s/[\,|\.|\!|\?|\:|\;]//g;
}
my %words_count; #The code I was told to add in this post.
$words_count{$_}++ for #words;
Next I read in the stop words I have in another array.
#Reading in the stopwords file
my $file1 = "stoplist.txt";
open(my $filehandle1, '<',$file1) or die "Could not open $file1\n";
my #stopwords;
while(my $line = <$filehandle1>){
chomp $line;
my #linearray = split(" ", $line);
push(#stopwords, #linearray);
}
for my $w (my #stopwords) {
s/\b\Q$w\E\B//ig;
}
Some notes about hashes in Perl... Problem description:
Anyway here is what I have so far I put a comment #WORKING ON MERGING ARRAY INTO HASH that is where I'm working at. I don't think the way I'm trying to put the array into the hash is right, but I looked online and the %hash{array} = "value"; doesn't compile. so not sure how else to do it.
At first, ask yourself why you want to "put the array into the hash". An array represents a list of values while a hash represents a set of key-value pairs. So you have to define what keys and values should be. Not only for us, but for you. It often helps to explain even simple things to get a better understanding.
In this case, you may want to count how often a given word $word occured in your #words array. This could be done by iterating over all words and increase $count{$word} by one each time. This is what #raina77ow did in his answer. Important here is, that you're accessing single hash values, which are represented with the scalar sigil $ in Perl. So if you have a hash named %count, you can increase the value for the key 'foo' by
$count{foo}++;
Your result of "online looking" above (%hash{array} = "value") doesn't make sense. There are three valid ways to store values in a hash:
set all key-value pairs by assingning a even-sized list to the whole hash:
%count = (hello => 42, world => 17);
set a single value for a given key by assigning a single value for a defined key (this is what we did before):
$count{hello} = 42;
set a list of values for a given list of keys using a so-called hash slice:
#count{qw(hello world)} = (42, 17);
Note the use of sigils here: % for a hashy even-sized list of keys and values mixed, $ for single (scalar) values and # for lists of values. In your example you're using %, but define an array in the key braces {...} and assign a single scalar value.
Well, if you have a list of words in #words array, and want to get a hash where each key refers to specific word, and each value is the quantity of this word appearances in the source array, it's done as simple as...
my %words_count;
$words_count{$_}++ for #words;
In other words (no pun intended), you iterate over #words array, for each member increasing by 1 the corresponding element of %words_count hash OR, when that element is not yet defined, essentially creating it with value 1 (so-called auto-vivification).
As a sidenote, calling keys function on arrays is close to meaningless: in 5.12+ it'll give you the list of indexes used instead, and before that, throw a syntax error at you.

A Perl script to process a CSV file, aggregating properties spread over multiple records

Sorry for the vague question, I'm struggling to think how to better word it!
I have a CSV file that looks a little like this, only a lot bigger:
550672,1
656372,1
766153,1
550672,2
656372,2
868194,2
766151,2
550672,3
868179,3
868194,3
550672,4
766153,4
The values in the first column are a ID numbers and the second column could be described as a property (for want of a better word...). The ID number 550672 has properties 1,2,3,4. Can anyone point me towards how I can begin solving how to produce strings such as that for all the ID numbers? My ideal output would be a new csv file which looks something like:
550672,1;2;3;4
656372,1;2
766153,1;4
etc.
I am very much a Perl baby (only 3 days old!) so would really appreciate direction rather than an outright solution, I'm determined to learn this stuff even if it takes me the rest of my days! I have tried to investigate it myself as best as I can, although I think I've been encumbered by not really knowing what to really search for. I am able to read in and parse CSV files (I even got so far as removing duplicate values!) but that is really where it drops off for me. Any help would be greatly appreciated!
I think it is best if I offer you a working program rather than a few hints. Hints can only take you so far, and if you take the time to understand this code it will give you a good learning experience
It is best to use Text::CSV whenever you are processing CSV data as all the debugging has already been done for you
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new;
open my $fh, '<', 'data.txt' or die $!;
my %data;
while (my $line = <$fh>) {
$csv->parse($line) or die "Invalid data line";
my ($key, $val) = $csv->fields;
push #{ $data{$key} }, $val
}
for my $id (sort keys %data) {
printf "%s,%s\n", $id, join ';', #{ $data{$id} };
}
output
550672,1;2;3;4
656372,1;2
766151,2
766153,1;4
868179,3
868194,2;3
Firstly props for seeking an approach not a solution.
As you've probably already found with perl, There Is More Than One Way To Do It.
The approach I would take would be;
use strict; # will save you big time in the long run
my %ids # Use a hash table with the id as the key to accumulate the properties
open a file handle on csv or die
while (read another line from the file handle){
split line into ID and property variable # google the split function
append new property to existing properties for this id in the hash table # If it doesn't exist already, it will be created
}
foreach my $key (keys %ids) {
deduplicate properties
print/display/do whatever you need to do with the result
}
This approach means you will need to iterate over the whole set twice (once in memory), so depending on the size of the dataset that may be a problem.
A more sophisticated approach would be to use a hashtable of hashtables to do the de duplication in the intial step, but depending on how quickly you want/need to get it working, that may not be worthwhile in the first instance.
Check out
this question
for a discussion on how to do the deduplication.
Well, open the file as stdin in perl, assume each row is of two columns, then iterate over all lines using left column as hash identifier, and gathering right column into an array pointed by a hash key. At the end of input file you'll get a hash of arrays, so iterate over it, printing a hash key and assigned array elements separated by ";" or any other sign you wish.
and here you go
dtpwmbp:~ pwadas$ cat input.txt
550672,1
656372,1
766153,1
550672,2
656372,2
868194,2
766151,2
550672,3
868179,3
868194,3
550672,4
766153,4
dtpwmbp:~ pwadas$ cat bb2.pl
#!/opt/local/bin/perl
my %hash;
while (<>)
{
chomp;
my($key, $value) = split /,/;
push #{$hash{$key}} , $value ;
}
foreach my $key (sort keys %hash)
{
print $key . "," . join(";", #{$hash{$key}} ) . "\n" ;
}
dtpwmbp:~ pwadas$ cat input.txt | perl -f bb2.pl
550672,1;2;3;4
656372,1;2
766151,2
766153,1;4
868179,3
868194,2;3
dtpwmbp:~ pwadas$
perl -F"," -ane 'chomp($F[1]);$X{$F[0]}=$X{$F[0]}.";".$F[1];if(eof){for(keys %X){$X{$_}=~s/;//;print $_.",".$X{$_}."\n"}}'
Another (not perl) way which incidentally is shorter and more elegant:
#!/opt/local/bin/gawk -f
BEGIN {FS=OFS=",";}
NF > 0 { IDs[$1]=IDs[$1] ";" $2; }
END { for (i in IDs) print i, substr(IDs[i], 2); }
The first line (after specifying the interpreter) sets the input FIELD SEPARATOR and the OUTPUT FIELD SEPARATOR to the comma. The second line checks of we have more than zero fields and if you do it makes the ID ($1) number the key and $2 the value. You do this for all lines.
The END statement will print these pairs out in an unspecified order. If you want to sort them you have to option of asorti gnu awk function or connecting the output of this snippet with a pipe to sort -t, -k1n,1n.

How do I print a hash name in Perl?

Kind of a simple question, but it has me stumped and google just lead me astray. All I want to do is print out the name of a hash. For example:
&my_sub(\%hash_named_bill);
&my_sub(\%hash_named_frank);
sub my_sub{
my $passed_in_hash = shift;
# do great stuff with the hash here
print "You just did great stuff with: ". (insert hash name here);
}
The part I don't know is how to get the stuff in the parenthesis(insert...). For a nested hash you can just use the "keys" tag to get the hash names (if you want to call them that). I can't figure out how to get the entire hash name though, it seems like it really is just another key.
As #hackattack said in the comment, the technical answer to your questions can be found in an answer to Get variable name as string in Perl
However, you should consider whether you are doing the right thing?
If you somehow need to know the name of the hash, you most likely would solve the problem better if you stash those multiple hashes into a hash-of-hashes with names being the keys (which you should be familiar with as you alluded to the approach in your question).
$hash_named_bill{name} = "bill";
$hash_named_frank{name} = "frank";
&my_sub(\%hash_named_bill);
&my_sub(\%hash_named_frank);
sub my_sub{
my $passed_in_hash = shift;
# do great stuff with the hash here
print "You just did great stuff with: ". $passed_in_hash->{name};
}
You can use a name to refer to a hash, but hashes themselves don't have names. For example, consider the following:
*foo = {};
*bar = \%foo;
$foo{x} = 3;
$bar{y} = 4;
Keeping in mind the hash contains (x=>3, y=>4): Is the hash nameless? named 'foo'? named 'bar'? All of the above? None of the above?
The best you can do is approximate an answer using PadWalker. I recommend against using it or similar (i.e. anything that finds a name) in production!
A hash is just a piece of memory, to which a name (or more than one) can be associated.
If you want to print the name of the variable, that's not very straightforward (see haccattack comment), and doesn't smell very well (are you sure you really need that?)
You can also (if this fits your scenario) consider "soft (or symbolic) references" :
%hash1 = ( x => 101, y => 501);
%hash2 = ( x => 102, y => 502);
my_sub("hash1");
#my_sub(\%hash1); # won't work
my_sub("hash2");
sub my_sub {
my $hashname = shift;
print "hash name: $hashname\n";
print $hashname->{x} . "\n";
}
Here you are passing to the function the name of the variable, instead of a (hard) reference to it. Notice that, in Perl, this feels equivalent at the time of dereferencing it (try uncommenting my_sub(\%hash1);), though it's quite a different thing.