evalEmpire / perl5i

A single module to fix as much of Perl 5 as possible in one go
http://search.cpan.org/perldoc?perl5i
Other
156 stars 42 forks source link

A universal object identifier #70

Closed schwern closed 14 years ago

schwern commented 14 years ago

A method which returns a unique object identifier for any object.

1) What to use? Rumor has it references can get reused. 2) Does reblessing an object change its ident? 3) What should the name be? id() is too generic. object_identifier()?

schwern commented 14 years ago

To clarify

my $obj = Foo->new;  my $other = $obj;  $obj->id eq $other->id;  # true
my $obj = Foo->new;  my $other = Foo->new;  $obj->id eq $other->id;  # false

Whether 42->id eq 42->id is up in the air. Argument against is that \42 will give you a different scalar ref each time. Argument for is that you can't change the contents. Possibly resolved by a stricter definition of object equality.

schwern commented 14 years ago

Simply using the reference of the object is a good first cut, but its not safe as references can be reused.

perl -wle 'my $id;  for(1..3) { my $obj = bless {}, "Foo";  print $obj }'
Foo=HASH(0x8039e8)
Foo=HASH(0x8039e8)
Foo=HASH(0x8039e8)

If you store the id of an object, and the object gets destroyed, you might find yourself with a different object but the same id again.

brunoV commented 14 years ago

Could an approach like this work? http://gist.github.com/310560

As far as I could tell, it behaves like Ruby's object_id: the id changes when the content of the variable changes, copying the variable to another retains the id, and reusing memory addresses with different content changes the id also.

Update: well, not quite: irb(main):003:0> 5.times { |i| foo = "foo"; puts foo.object_id } -608671988 -608671868 -608671918 -608671998 -608672108 => 5

schwern commented 14 years ago

The problem there is when the contents of the object change, the id change. We want the id to remain immutable over the life of the object.

Your code does bring up the idea of combining the reference with some sort of salt to make it unique. The issue then is storing it. That's what the meta object would be for, but then you have to be able to repeatedly find an object's meta object which requires... an object ID. Catch 22.

Overriding bless() may be the way out. Essentially, bless() checks to see if the freshly minted object has the same ref as a previous object. If so, it appends a simple salt to the id. The down side is this requires recording the ref of every object ever made in the process which will be a memory hog.

chocolateboy commented 14 years ago

http://gist.github.com/335691

schwern commented 14 years ago

@chocolateboy I presume you're suggesting using refaddr() as the ID? Its immutable, but it still relies on reference addresses which Perl will reuse. This means if someone stores an object ID, and the object gets destroyed, its possible a completely unrelated object will get the same ID and cause a false match.

Here's a test. Can you write an id() which passes? http://gist.github.com/335741

schwern commented 14 years ago

The winner is vincent!

{ my $last = 0; Hash::Util::FieldHash::fieldhash(my %id); sub UNIVERSAL::id { my $self = shift; exists $id{$self} ? $id{$self} : ($id{$self} = ++$last) } }

http://codepad.org/Q0DfhvqK

chocolateboy commented 14 years ago

Nice!

schwern commented 14 years ago

I've written Object::ID to implement this independently.

schwern commented 14 years ago

Implemented and will be in 2.2