Herkum has asked for the wisdom of the Perl Monks concerning the following question:

I am using Class::Std to generate my objects. What I am trying to do is check to see if an object of the same class and id (a property) already exists and then use the existing object instead of trying to create a new instance of it.
my $manager1 = Manager->new({ id => 1 }); my $manager2 = Manager->new({ id => 1 }); if ($manager1 eq $manager2) { print "They are the same object\n"; } else { print "They are different objects\n"; }
Does anyone have any suggestions on how to do this?

Replies are listed 'Best First'.
Re: Class::Std problem
by rhesa (Vicar) on Dec 20, 2006 at 22:05 UTC
    Your issue isn't specific to Class::Std objects. In Perl, the default stringification of an object contains its class name and its memory address, so different instances will generate a different string.

    If you want to use eq, you should overload stringification ('""') or comparison (cmp). See overload for details.

    Another approach would be to implement an equals method, and check if( $manager1->equals( $manager2 ) ).

      Howdy!

      I take the question to be "how do I fix my 'new' so the code snipped works right?" If new({ id => 1 }) returns the same thing each time, the comparison should work fine. The trick is to get 'new' to not only construct one object for each distinct value of id that it sees.

      yours,
      Michael

        This was more along the lines of what I was looking for. I must have not made the problem clear enough because most of the posts focus upon the comparison aspect rather than the object generation.

        I use Class::Std to generate new objects. However, if I am getting an object that already exists, I wanted to return the existing object, not generate a new one for comparison. So in my example, if $manager1 was this 'Manager=SCALAR(0x83ef950)' then $manager2 would return the reference.

        After sleeping on it, I think that I just have to sub-class Class::Std that keeps track of all the existing objects and returns that object if it already exists.

Re: Class::Std problem
by duckyd (Hermit) on Dec 20, 2006 at 22:05 UTC
    I don't think your problem has anything to do with Class::Std per se. You need to overload "eq" to compare your object ids. E.G.
    #!/usr/local/bin/perl use strict; use warnings; my $manager1 = Manager->new({ id => 1 }); my $manager2 = Manager->new({ id => 1 }); my $manager3 = Manager->new({ id => 3 }); compare( $manager1, $manager2 ); compare( $manager1, $manager3 ); sub compare { my ( $obj1, $obj2 ) = @_; if ($obj1 eq $obj2) { print "They are the same object\n"; }else { print "They are different objects\n"; } } package Manager; use overload 'eq' => sub { $_[0]->{id} == $_[1]->{id} } ; sub new { my ( $class, $args ) = @_; $args ||= {}; return bless $args, $class; }
    output:
    They are the same object They are different objects
Re: Class::Std problem
by chargrill (Parson) on Dec 20, 2006 at 23:20 UTC

    Perhaps Data::Compare would come in handy?

    And depending on your purposes for comparison, Class::MakeMethods::Utility::Ref looks like it's ref_compare() function might be of some use, too.



    --chargrill
    s**lil*; $*=join'',sort split q**; s;.*;grr; &&s+(.(.)).+$2$1+; $; = qq-$_-;s,.*,ahc,;$,.=chop for split q,,,reverse;print for($,,$;,$*,$/)
Re: Class::Std problem
by herveus (Prior) on Dec 21, 2006 at 12:13 UTC
    Howdy!

    Your constructor (new) will need to do the heavy lifting. 'new' will need to check the list of objects it has already created to see if the given id is already in use so it can return that object instead of creating a new one.

    In essence, you want to establish a registry of objects. A hash whose keys are the 'id' values would do the trick. 'new' will first check the hash and create a new instance only if it's not already in the hash.

    You are looking for what the Gang of Four calls the Flyweight pattern.

    yours,
    Michael