How do I print a hash name in Perl? - 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.

Related

Deferencing hash of hashes in 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.

Change ref of hash in Perl

I ran into this and couldn't find the answer. I am trying to see if it is possible to "change" the reference of a hash. In other words, I have a hash, and a function that returns a hashref, and I want to make my hash point to the location in memory specified by this ref, instead of copying the contents of the hash it points to. The code looks something like this:
%hash = $h->hashref;
My obvious guess was that it should look like this:
\%hash = $h->hashref;
but that gives the error:
Can't modify reference constructor in scalar assignment
I tried a few other things, but nothing worked. Is what I am attempting actually possible?
An experimental feature which would seemingly allow you to do exactly what you're describing has been added to Perl 5.21.5, which is a development release (see "Aliasing via reference").
It sounds like you want:
use Data::Alias;
alias %hash = $h->hashref;
Or if %hash is a package variable, you can instead just do:
*hash = $h->hashref;
But either way, this should almost always be avoided; simply use the hash reference.
This question is really old, but Perl now allows this sort of thing as an experimental feature:
use v5.22;
use experimental qw(refaliasing);
my $first = {
foo => 'bar',
baz => 'quux',
};
\my %hash = $first;
Create named variable aliases with ref aliasing
Mix assignment and reference aliasing with declared_refs
Yes, but…
References in Perl are scalars. You are trying to alias the return value. This actually is possible, but you should not do this, since it involves messing with the symbol table. Furthermore, this only works for globals (declared with our): If you assign a hashref to the glob *hash it will assign to the symbol table entry %hash:
#!/usr/bin/env perl
use warnings;
use strict;
sub a_hashref{{a => "one", b => "two"}}
our %hash;
*hash = a_hashref;
printf "%3s -> %s\n", $_, $hash{$_} foreach keys %hash;
This is bad style! It isn't in PBP (directly, but consider section 5.1: “non-lexicals should be avoided”) and won't be reported by perlcritic, but you shouldn't pollute the package namespace for a little syntactic fanciness. Furthermore it doesn't work with lexical variables (which is what you might want to use most of the time, because they are lexically scoped, not package wide).
Another problem is, that if the $h->hashref method changes its return type, you'll suddenly assign to another table entry! (So if $h->hashref changes its return type to an arrayref, you assign to #hash, good luck detecting that). You could circumvent that by checking if $h->hashref really returns a hashref with 'HASH' eq ref $h->hashref`, but that would defeat the purpose.
What is the problem with just keeping the reference? If you get a reference, just store it in a scalar:
$hash = $h->hashref
To read more about the global symbol table, take a look at perlmod and consider perlref for the *FOO{THING} syntax, which sadly isn't for lvalues.
To achieve what you want, you could check out the several aliasing modules on cpan. Data::Alias or Lexical::Alias seem to fit your purpose. Also if you are interested in tie semantics and/or don't want to use XS modules, Tie::Alias might be worth a shoot.

Perl $$var -- two dollar signs as a sigil?

This seems like something I should be able to easily Google, Bing, or DDG, but I'm coming up completely empty on everything.
Basically, I'm tasked with (in part) rewriting a set of old Perl scripts. Not being a Perl programmer myself, there's definitely a learning curve in reading these scripts to figure out what they're doing, but I've hit an absolute brick wall with lines like this one:
$comment = $$LOC{'DESCRIPTION'};
Near as I can tell, the right-hand side is a dictionary, or more precisely it's getting the value referenced by the key 'DESCRIPTION' in said dictionary. But what's with the "extra" dollar sign in front of it?
It looks suspiciously like PHP's variable variables, but after scouring search engines, assorted StackExchange sites, and perlvar, I can't find any indication that Perl even has such a feature, let alone that this is how it's invoked. The most I've turned up is that '$' is not a valid character in a variable name, so I know $$LOC is not merely calling up a variable that just happens to be named $LOC.
What is this extra dollar sign doing here?
This is an alternative form of dereferencing. Could (and honestly probably should) be written as:
$LOC->{'DESCRIPTION'};
You'll sometimes see the same with other all basic data types:
my $str = 'a string';
my %hash = (a => 1, b => 2);
my #array = (1..4);
my $strref = \$str;
my $hashref = \%hash;
my $arrayref = \#array;
print "String value is $$strref\n";
print "Hash values are either $$hashref{a} or $hashref->{b}\n";
print "Array values are accessed by either $$arrayref[0] or $arrayref->[2]\n";
Dereferencing is treating a scalar as the 'address' at which you can locate another variable (scalar, array, or hash) and its value.
In this case, $LOC{DESCRIPTION} is being interpreted as the address of another scalar, which is read into $comment.
In Perl,
my $str = 'some val';
my $ref = \$str;
my $val = ${$ref};
my $same_val = $$ref;

concept of hash in perl [duplicate]

I would like to properly understand hashes in Perl. I've had to use Perl intermittently for quite some time and mostly whenever I need to do it, it's mostly related to text processing.
And everytime, I have to deal with hashes, it gets messed up. I find the syntax very cryptic for hashes
A good explanation of hashes and hash references, their differences, when they are required etc. would be much appreciated.
A simple hash is close to an array. Their initializations even look similar. First the array:
#last_name = (
"Ward", "Cleaver",
"Fred", "Flintstone",
"Archie", "Bunker"
);
Now let's represent the same information with a hash (aka associative array):
%last_name = (
"Ward", "Cleaver",
"Fred", "Flintstone",
"Archie", "Bunker"
);
Although they have the same name, the array #last_name and the hash %last_name are completely independent.
With the array, if we want to know Archie's last name, we have to perform a linear search:
my $lname;
for (my $i = 0; $i < #last_name; $i += 2) {
$lname = $last_name[$i+1] if $last_name[$i] eq "Archie";
}
print "Archie $lname\n";
With the hash, it's much more direct syntactically:
print "Archie $last_name{Archie}\n";
Say we want to represent information with only slightly richer structure:
Cleaver (last name)
Ward (first name)
June (spouse's first name)
Flintstone
Fred
Wilma
Bunker
Archie
Edith
Before references came along, flat key-value hashes were about the best we could do, but references allow
my %personal_info = (
"Cleaver", {
"FIRST", "Ward",
"SPOUSE", "June",
},
"Flintstone", {
"FIRST", "Fred",
"SPOUSE", "Wilma",
},
"Bunker", {
"FIRST", "Archie",
"SPOUSE", "Edith",
},
);
Internally, the keys and values of %personal_info are all scalars, but the values are a special kind of scalar: hash references, created with {}. The references allow us to simulate "multi-dimensional" hashes. For example, we can get to Wilma via
$personal_info{Flintstone}->{SPOUSE}
Note that Perl allows us to omit arrows between subscripts, so the above is equivalent to
$personal_info{Flintstone}{SPOUSE}
That's a lot of typing if you want to know more about Fred, so you might grab a reference as sort of a cursor:
$fred = $personal_info{Flintstone};
print "Fred's wife is $fred->{SPOUSE}\n";
Because $fred in the snippet above is a hashref, the arrow is necessary. If you leave it out but wisely enabled use strict to help you catch these sorts of errors, the compiler will complain:
Global symbol "%fred" requires explicit package name at ...
Perl references are similar to pointers in C and C++, but they can never be null. Pointers in C and C++ require dereferencing and so do references in Perl.
C and C++ function parameters have pass-by-value semantics: they're just copies, so modifications don't get back to the caller. If you want to see the changes, you have to pass a pointer. You can get this effect with references in Perl:
sub add_barney {
my($personal_info) = #_;
$personal_info->{Rubble} = {
FIRST => "Barney",
SPOUSE => "Betty",
};
}
add_barney \%personal_info;
Without the backslash, add_barney would have gotten a copy that's thrown away as soon as the sub returns.
Note also the use of the "fat comma" (=>) above. It autoquotes the string on its left and makes hash initializations less syntactically noisy.
The following demonstrates how you can use a hash and a hash reference:
my %hash = (
toy => 'aeroplane',
colour => 'blue',
);
print "I have an ", $hash{toy}, " which is coloured ", $hash{colour}, "\n";
my $hashref = \%hash;
print "I have an ", $hashref->{toy}, " which is coloured ", $hashref->{colour}, "\n";
Also see perldoc perldsc.
A hash is a basic data type in Perl.
It uses keys to access its contents.
A hash ref is an abbreviation to a
reference to a hash. References are
scalars, that is simple values. It is
a scalar value that contains
essentially, a pointer to the actual
hash itself.
Link: difference between hash and hash ref in perl - Ubuntu Forums
A difference is also in the syntax for deleting. Like C, perl works like this for Hashes:
delete $hash{$key};
and for Hash References
delete $hash_ref->{$key};
The Perl Hash Howto is a great resource to understand Hashes versus Hash with Hash References
There is also another link here that has more information on perl and references.
See perldoc perlreftut which is also accessible on your own computer's command line.
A reference is a scalar value that refers to an entire array or an entire hash (or to just about anything else). Names are one kind of reference that you're already familiar with. Think of the President of the United States: a messy, inconvenient bag of blood and bones. But to talk about him, or to represent him in a computer program, all you need is the easy, convenient scalar string "Barack Obama".
References in Perl are like names for arrays and hashes. They're Perl's private, internal names, so you can be sure they're unambiguous. Unlike "Barack Obama", a reference only refers to one thing, and you always know what it refers to. If you have a reference to an array, you can recover the entire array from it. If you have a reference to a hash, you can recover the entire hash. But the reference is still an easy, compact scalar value.

What's the difference between a hash and hash reference in Perl?

I would like to properly understand hashes in Perl. I've had to use Perl intermittently for quite some time and mostly whenever I need to do it, it's mostly related to text processing.
And everytime, I have to deal with hashes, it gets messed up. I find the syntax very cryptic for hashes
A good explanation of hashes and hash references, their differences, when they are required etc. would be much appreciated.
A simple hash is close to an array. Their initializations even look similar. First the array:
#last_name = (
"Ward", "Cleaver",
"Fred", "Flintstone",
"Archie", "Bunker"
);
Now let's represent the same information with a hash (aka associative array):
%last_name = (
"Ward", "Cleaver",
"Fred", "Flintstone",
"Archie", "Bunker"
);
Although they have the same name, the array #last_name and the hash %last_name are completely independent.
With the array, if we want to know Archie's last name, we have to perform a linear search:
my $lname;
for (my $i = 0; $i < #last_name; $i += 2) {
$lname = $last_name[$i+1] if $last_name[$i] eq "Archie";
}
print "Archie $lname\n";
With the hash, it's much more direct syntactically:
print "Archie $last_name{Archie}\n";
Say we want to represent information with only slightly richer structure:
Cleaver (last name)
Ward (first name)
June (spouse's first name)
Flintstone
Fred
Wilma
Bunker
Archie
Edith
Before references came along, flat key-value hashes were about the best we could do, but references allow
my %personal_info = (
"Cleaver", {
"FIRST", "Ward",
"SPOUSE", "June",
},
"Flintstone", {
"FIRST", "Fred",
"SPOUSE", "Wilma",
},
"Bunker", {
"FIRST", "Archie",
"SPOUSE", "Edith",
},
);
Internally, the keys and values of %personal_info are all scalars, but the values are a special kind of scalar: hash references, created with {}. The references allow us to simulate "multi-dimensional" hashes. For example, we can get to Wilma via
$personal_info{Flintstone}->{SPOUSE}
Note that Perl allows us to omit arrows between subscripts, so the above is equivalent to
$personal_info{Flintstone}{SPOUSE}
That's a lot of typing if you want to know more about Fred, so you might grab a reference as sort of a cursor:
$fred = $personal_info{Flintstone};
print "Fred's wife is $fred->{SPOUSE}\n";
Because $fred in the snippet above is a hashref, the arrow is necessary. If you leave it out but wisely enabled use strict to help you catch these sorts of errors, the compiler will complain:
Global symbol "%fred" requires explicit package name at ...
Perl references are similar to pointers in C and C++, but they can never be null. Pointers in C and C++ require dereferencing and so do references in Perl.
C and C++ function parameters have pass-by-value semantics: they're just copies, so modifications don't get back to the caller. If you want to see the changes, you have to pass a pointer. You can get this effect with references in Perl:
sub add_barney {
my($personal_info) = #_;
$personal_info->{Rubble} = {
FIRST => "Barney",
SPOUSE => "Betty",
};
}
add_barney \%personal_info;
Without the backslash, add_barney would have gotten a copy that's thrown away as soon as the sub returns.
Note also the use of the "fat comma" (=>) above. It autoquotes the string on its left and makes hash initializations less syntactically noisy.
The following demonstrates how you can use a hash and a hash reference:
my %hash = (
toy => 'aeroplane',
colour => 'blue',
);
print "I have an ", $hash{toy}, " which is coloured ", $hash{colour}, "\n";
my $hashref = \%hash;
print "I have an ", $hashref->{toy}, " which is coloured ", $hashref->{colour}, "\n";
Also see perldoc perldsc.
A hash is a basic data type in Perl.
It uses keys to access its contents.
A hash ref is an abbreviation to a
reference to a hash. References are
scalars, that is simple values. It is
a scalar value that contains
essentially, a pointer to the actual
hash itself.
Link: difference between hash and hash ref in perl - Ubuntu Forums
A difference is also in the syntax for deleting. Like C, perl works like this for Hashes:
delete $hash{$key};
and for Hash References
delete $hash_ref->{$key};
The Perl Hash Howto is a great resource to understand Hashes versus Hash with Hash References
There is also another link here that has more information on perl and references.
See perldoc perlreftut which is also accessible on your own computer's command line.
A reference is a scalar value that refers to an entire array or an entire hash (or to just about anything else). Names are one kind of reference that you're already familiar with. Think of the President of the United States: a messy, inconvenient bag of blood and bones. But to talk about him, or to represent him in a computer program, all you need is the easy, convenient scalar string "Barack Obama".
References in Perl are like names for arrays and hashes. They're Perl's private, internal names, so you can be sure they're unambiguous. Unlike "Barack Obama", a reference only refers to one thing, and you always know what it refers to. If you have a reference to an array, you can recover the entire array from it. If you have a reference to a hash, you can recover the entire hash. But the reference is still an easy, compact scalar value.