Take the 2-minute tour ×

It seems that Perl can only have strings as the keys of a hash. (Has this been changed in a certain version of Perl?) It is very limiting to only be able to use strings as the key. What if I wanted an object or an array to be the key? In Python it is easy to use an array, tuple, and other objects that can compare, as dict keys. Perl does have the ability to compare things like arrays for equality, so I don't see why they can't be used as mapping-type keys.

Isn't there a way to use any key type in Perl? Is there a module that provides this?

share|improve this question
add comment

4 Answers

Yes it does, use fieldhashes (Hash::Util::FieldHash for 5.10+ and Hash::Util::FieldHash::Compat for before 5.10) to register your hashes as fieldhashes, and you can use any reference (and thus, any object) as a key for those hashes (it numifies the reference, essentially, and provides logic for dealing with CLONEing across threads and garbage collecting the keys), for example:

use Hash::Util qw/fieldhashes/;
fieldhashes \my (%foo, %bar, %baz);

my %data = (a => 1, b => 2, c => 3);
my $stuff = {t => 2, u => 3, l => 9};
$foo{\%data} = 'x';
$foo{$stuff} = 'a';
$bar{\%data} = 'y';
$bar{$stuff} = 'b';
$baz{\%data} = 'z';
$baz{$stuff} = 'c';

print "$foo{\%data} $bar{\%data} $baz{\%data}\n";
print "$foo{$stuff} $bar{$stuff} $baz{$stuff}\n";
share|improve this answer
add comment

Yes, there is module for this on CPAN: Tie::Hash::StructKeyed. It takes into account whole structure, but as a snapshot. each/keys will return original reference.

share|improve this answer
add comment

AFAIK Perl simply stringifies the keys?

package Foo;

use Moose;
use overload ('""' => \&stringify);

sub stringify {
    return "xxx";

package main;

use v5.10;
use Data::Dump 'pp';

my $foo = Foo->new;
my $hash = {$foo => 'bar'};
say pp($hash); // { xxx => "bar" }

This way you can also use whatever you want as a hash key. See also this thread on Perl Monks.

As for the equality, take a look at equality operators in perlop. The == operator compares numerically, the eq operator compares stringwise. This means that for example (4, 2) == (1, 2) is true (as scalar (4, 2) is 2), which might be a surprise for you.

share|improve this answer
add comment

Contrary to what you said, Perl does NOT have the ability to compare things like arrays for equality as you claim. For starters, Perl has no definition for array equality. And if the definition requires comparing the contents of the array, then Perl doesn't have definitions of equality for most things that can be found in an array either.

The closest Perl has for a definition of equality arrays is their address. If that's what you want to use, then it's quite easy:

$key = ['a', 'b'];
$hash{$key} = [ $key, $val ];   # Prevents the key from being freed.
print $hash{$key}[1];

Otherwise, Perl leaves it up to you to implement what you want instead of forcing you to use what it provides. I see two main approaches.

A tied hash, basically code that presents the interface of a hash without actually being a hash table, can support any key type. You could use it to define your version of array equality. There might even be an existing module (although I didn't see one after a very quick search).

Another approach would be to create a function that produces a unique key from the key expression.

sub key{ "@_" }  # Overly simplistic?
$hash{key('a', 'b')} = $val;
print $hash{key('a', 'b')};
share|improve this answer
Perl also can compare content of arrays: print 'ok' if (['a',1] ~~ ['a',1]); –  Alexandr Ciornii Aug 16 '11 at 9:41
add comment

Your Answer


