Q:

how to use reference of hashes in perl

I'm trying to learn the reference function, but I can't figure out a way to put hashes in reference at the same time. I want to write a subroutine that will take two simple hash references as arguments and to check whether these two hashes are equal or not. My code is:
#!/usr/bin/perl

use strict;
use warnings;
use feature qw(say);

my $hash1_r = {ITALY => "ROME",
            FRANCE => "PARIS"};
my $hash2_r = {ITALY => "MILAN",
            FRANCE => "PARIS"};
my $hash3_r = {ITALY => "ROME"};
my $hash4_r = {SPAIN => "ROME",
            FRANCE => "PARIS"};

sub compareHashes(%$hash1, %$hash2){
    my $hash1; my $hash2;   
    for (my $i =0; $i < keys %$hash1; $i++){
        say "The first hash:";
        say "keys %$hash1\t, values %$hash1";
    }
    for (my $i =0; $i < keys %$hash2; $i++){
            say "The second hash:";
            say "keys %$hash2\t, values %$hash2";
    }

    for (keys %$hash1) {
        if (keys %$hash1 ne keys %$hash2){
            say "Two above hashes are not equal";
        }elsif (my $key1 (keys %$hash1) ne my $key2 (keys %$hash2)){
            say "Two above hashes are not equal";
        }elsif (%$hash1->{$_} ne %$hash2->{$_}){
            say "Two above hashes are not equal";
        }else {
            say "Two above hashes are equal";
        }
    }
}

compareHashes (%$hash1_r, %$hash1_r);
compareHashes (%$hash1_r, %$hash2_r);
compareHashes (%$hash1_r, %$hash3_r);
compareHashes (%$hash1_r, %$hash4_r);

However, I got those errors:
Prototype after '%' for main::compareHashes : %$hash1,%$hash2 at compareHashes2.pl line 16.
Illegal character in prototype for main::compareHashes : %$hash1,%$hash2 at compareHashes2.pl line 16.
syntax error at compareHashes2.pl line 30, near "$key1 ("
syntax error at compareHashes2.pl line 32, near "}elsif"
Global symbol "$hash2" requires explicit package name at compareHashes2.pl line 32.

Any solutions? Any help will be greatly appreciated!

A:

I would recommend reading the following excellent perl documentation for the general idea:
perldoc perlreftut
A slight simplification of your code, getting the references to work:
#!/usr/bin/perl

use strict;
use warnings;
use feature qw(say);

# { ... } creates a hash reference, you can pass this to a function directly
my $hash1_r = { ITALY => "ROME",  FRANCE => "PARIS" };
my $hash2_r = { ITALY => "MILAN", FRANCE => "PARIS" };
my $hash3_r = { ITALY => "ROME"                     };
my $hash4_r = { SPAIN => "ROME",  FRANCE => "PARIS" };

sub compareHashes {
    my ($hash1, $hash2) = @_;   # @_ is the default array

    # You can just use hash references directly by prepending with a '%' symbol
    # when you need the actual hash, such as when using 'keys', 'values', 'each', etc.
    # You can access the elements by using an arrow: $hashref->{'key_name'}

    say "-"x40;
    say "The first hash:";
    while ( my ($key, $value) = each %$hash1 ) {
        say "$key => $value";
    }

    say "The second hash:";
    while ( my ($key, $value) = each %$hash2 ) {
        say "$key => $value";
    }

    my (@keys1) = keys %$hash1;
    my ($nkey1) = scalar @keys1;

    my (@keys2) = keys %$hash2;
    my ($nkey2) = scalar @keys2;
    if ($nkey1 != $nkey2) {
        say "=> unequal number of keys: $nkey1 vs $nkey2";
        return 0;  # False, the hashes are different, we don't need to test any further
    }

    # Create a new hash using all of the keys from hash1 and hash2
    # The effect is to eliminate duplicates, as repeated keys, i.e.
    # common to both hash1 and hash2 will just produce one key in %uniq
    # You can use the 'uniq' function from List::MoreUtils to achieve
    # the same thing.      
    # In perl, using a hash to eliminate duplicates, or test for set
    # membership is a very common idiom.
    # The 'map' function iterates over a list and performs the 
    # operation inside the curly braces {...}, returning all
    # of the results.
    # For example:  map { 2 * $_ } ( 1,2,3 )     # ( 2,4,6 )
    # If you assign a list to a hash, it takes pairs of values
    # and turns them into key/value pairs
    # The '=>' is equivalent to a ',' but makes the intent easier
    # to understand
    my %uniq = map { $_ => 1 } ( @keys1, @keys2 );
    my $nuniqkey = scalar keys %uniq;
    if ($nkey1 != $nuniqkey) {
        say "=> unequal set of keys";
        return 0; # False, the hashes are different, we don't need to test any further
    }

    # Now test the values
    # If we neglected to check for uniqueness in the above block,
    # we would run into the situation where hash1 might have a key
    # that hash2 doesn't have (and vice-versa).  This would trigger a
    # 'use of uninitialized value' warning in the comparison operator
    for my $key (@keys1) {
        my ($value1) = $hash1->{$key};
        my ($value2) = $hash2->{$key};
        if ($value1 ne $value2) {
            say "=> unequal values for key '$key' : $value1 vs $value2";
            return 0; # False, the hashes are different, we don't need to test any further
        }
    }

    say "=> equal, yay!";
    return 1; # True, the hashes are equal after all!
}

compareHashes($hash1_r, $hash1_r);
compareHashes($hash1_r, $hash2_r);
compareHashes($hash1_r, $hash3_r);
compareHashes($hash1_r, $hash4_r);

A:

You have a good answer that you have already accepted. But for people finding this question in the future, I think it's worth explaining some of the errors you have made.
You start by defining some anonymous hashes. That's fine.
my $hash1_r = {
  ITALY => "ROME",
  FRANCE => "PARIS"
};
my $hash2_r = {
  ITALY => "MILAN",
  FRANCE => "PARIS"
};
my $hash3_r = {
  ITALY => "ROME"
};
my $hash4_r = {
  SPAIN => "ROME",
  FRANCE => "PARIS"
};

I'm now going to skip to where you call your subroutine (I'll get back to the subroutine itself soon).
compareHashes (%$hash1_r, %$hash1_r);
compareHashes (%$hash1_r, %$hash2_r);
compareHashes (%$hash1_r, %$hash3_r);
compareHashes (%$hash1_r, %$hash4_r);

One of the most important uses for references is to enable you to pass multiple arrays and hashes into a subroutine without them being flattened into a single array. As you have hash references already, it would make sense to pass those references into the subroutine. But you don't do that. You dereference your hashes which means you send the actual hashes into the subroutine. That means that, for example, your first call passes in the list ('ITALY', 'ROME', 'FRANCE', 'PARIS', 'ITALY', 'MILAN', 'FRANCE', 'PARIS'). And there is no way for the code inside your subroutine to separate that list into two hashes.
Now, let's look at the subroutine itself. You start by defining a prototype for the subroutine. In most cases, prototypes are unnecessary. In many cases, they change the code behaviour in hard-to-understand ways. No Perl expert would recommend using prototypes in this code. And, as your error message says, you get the prototype wrong.
sub compareHashes(%$hash1, %$hash2){

I'm not sure what you were trying to do with this prototype. Perhaps it's not a prototype at all - perhaps it's a function signature (but if it was, you would need to turn the feature on).
On the next line, you declare two variables. Variables that you never give values to.
my $hash1; my $hash2;   

There are then two very confused for loops.
for (my $i =0; $i < keys %$hash1; $i++){
    say "The first hash:";
    say "keys %$hash1\t, values %$hash1";
}

$hash1 has no value. So %$hash1 is zero (the hash has no keys) and the loop isn't executed. But we're not missing much as the loop body just prints the same uninitialised values each time.
And you could simplify your for loop by making it a foreach-style loop.
foreach my $i (0 .. keys %$hash1 - 1) { ... }

Or (given that you don't use $i at all:
foreach (1 .. keys %$hash1) { ... }

After another, equally ineffective, for loop for $hash2, you try to compare your two hashes.
for (keys %$hash1) {
    if (keys %$hash1 ne keys %$hash2){
        say "Two above hashes are not equal";
    }elsif (my $key1 (keys %$hash1) ne my $key2 (keys %$hash2)){
        say "Two above hashes are not equal";
    }elsif (%$hash1->{$_} ne %$hash2->{$_}){
        say "Two above hashes are not equal";
    }else {
        say "Two above hashes are equal";
    }
}

I have no idea at all why this is all in a for loop. but your comparisons do nothing to actually compare the values in the hash. All you are comparing is the number of keys in the hashes (which are always going to be equal here - as your hashes are always empty).
All in all, this is the work who is extremely confused about how hashes, subroutines and references work in Perl. I would urge you to stop what you are doing and take the time to work through a good reference book like Learning Perl followed by Intermediate Perl before you continue down your current route and just confuse yourself more.

