In addition to the other posts comments, even if you do get a unique object identifer, if you don't create a reference to that object somewhere other than in the hash key, the object might fall out of scope, get garbage collected, and become inaccessable.
Take a look at this code sample and what it produces:
use strict;
use warnings;
$|++;
{
package X;
use Moose;
has side => ( isa => 'Str', is => 'rw', required => 1 );
has foo => ( isa => 'Int', is => 'rw', required => 1 );
sub DEMOLISH {
my ( $self ) = @_ ;
printf "Destroyed %i ( %s )\n" , $self->foo, $self->side;
}
__PACKAGE__->meta->make_immutable;
}
{
package Y;
my $hash = {};
for ( 1 .. 5 ){
print "Creating $_ \n";
my $k = X->new( foo => $_ , side => 'key' );
my $v = X->new( foo => $_, side => 'value' );
$hash->{$k} = $v;
print "Created $_ at $k \n";
}
for ( keys %$hash ){
print "Emptying Hash slowly, doing key $_ \n";
delete $hash->{$_};
}
}
Outputs:
Creating 1
Created 1 at X=HASH(0x2597d08)
Destroyed 1 ( key )
Creating 2
Created 2 at X=HASH(0x2fca7c0)
Destroyed 2 ( key )
Creating 3
Created 3 at X=HASH(0x2fca808)
Destroyed 3 ( key )
Creating 4
Destroyed 1 ( value )
Created 4 at X=HASH(0x2597d08)
Destroyed 4 ( key )
Creating 5
Created 5 at X=HASH(0x2597d68)
Destroyed 5 ( key )
Emptying Hash slowly, doing key X=HASH(0x2597d68)
Destroyed 5 ( value )
Emptying Hash slowly, doing key X=HASH(0x2597d08)
Destroyed 4 ( value )
Emptying Hash slowly, doing key X=HASH(0x2fca808)
Destroyed 3 ( value )
Emptying Hash slowly, doing key X=HASH(0x2fca7c0)
Destroyed 2 ( value )
You'll see that every single key object got GC'd at the end of the loop due to there no longer being any reference to it.
And you'll see an additional fun thing, that the key-object we generated for "4" used the same memory address as "1", so when we replaced its value in the hash, the value was also GC'd. :/
Solving this issue is reasonably simple, and here is one way to do it:
use strict;
use warnings;
$|++;
{
package X;
use Moose;
use Data::UUID;
my $ug = Data::UUID->new();
has side => ( isa => 'Str', is => 'rw', required => 1 );
has foo => ( isa => 'Int', is => 'rw', required => 1 );
has uuid => ( isa => 'Str', is => 'rw', required => 1 , builder => '_build_uuid' );
sub _build_uuid {
return $ug->create_str();
}
sub DEMOLISH {
my ( $self ) = @_ ;
printf "Destroyed %i ( %s , %s )\n" , $self->foo, $self->side, $self->uuid;
}
__PACKAGE__->meta->make_immutable;
}
{
package Y;
my $hash = {};
my $keys = {};
for ( 1 .. 5 ){
print "Creating $_ \n";
my $k = X->new( foo => $_ , side => 'key' );
my $v = X->new( foo => $_, side => 'value' );
$keys->{$k->uuid} = $k;
$hash->{$k->uuid} = $v;
print "Created $_ at $k \n";
}
for ( sort keys %$hash ){
print "Emptying Hash slowly, doing key $_ \n";
delete $hash->{$_};
delete $keys->{$_};
}
}
Output:
Creating 1
Created 1 at X=HASH(0x2a12b58)
Creating 2
Created 2 at X=HASH(0x2a0d068)
Creating 3
Created 3 at X=HASH(0x2a28960)
Creating 4
Created 4 at X=HASH(0x2a28b28)
Creating 5
Created 5 at X=HASH(0x2a28c18)
Emptying Hash slowly, doing key ADD9C702-E254-11DF-A4A3-F48B02F52B7F
Destroyed 1 ( value , ADD9CA18-E254-11DF-A4A3-F48B02F52B7F )
Destroyed 1 ( key , ADD9C702-E254-11DF-A4A3-F48B02F52B7F )
Emptying Hash slowly, doing key ADD9CBD0-E254-11DF-A4A3-F48B02F52B7F
Destroyed 2 ( value , ADD9CCD4-E254-11DF-A4A3-F48B02F52B7F )
Destroyed 2 ( key , ADD9CBD0-E254-11DF-A4A3-F48B02F52B7F )
Emptying Hash slowly, doing key ADD9CE5A-E254-11DF-A4A3-F48B02F52B7F
Destroyed 3 ( value , ADD9CF5E-E254-11DF-A4A3-F48B02F52B7F )
Destroyed 3 ( key , ADD9CE5A-E254-11DF-A4A3-F48B02F52B7F )
Emptying Hash slowly, doing key ADD9D0DA-E254-11DF-A4A3-F48B02F52B7F
Destroyed 4 ( value , ADD9D1DE-E254-11DF-A4A3-F48B02F52B7F )
Destroyed 4 ( key , ADD9D0DA-E254-11DF-A4A3-F48B02F52B7F )
Emptying Hash slowly, doing key ADD9D38C-E254-11DF-A4A3-F48B02F52B7F
Destroyed 5 ( value , ADD9D49A-E254-11DF-A4A3-F48B02F52B7F )
Destroyed 5 ( key , ADD9D38C-E254-11DF-A4A3-F48B02F52B7F )