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

I wish to compare two objects to determine if the attribute values are the same. I'm finding very little guidance on this issue anywhere. There is the Data::Compare module but from what I gather I will need to write my own plugin module to do the comparison. I'd be stunned if there is nothing out there that makes it trivial to compare the attributes of two objects against one another but I can't find it.

Any ideas?

Update

Here are the class attributes (written with Moose syntax)

has 'start_time' => ( is => 'rw', isa => 'Time::Piece', ); has 'end_time' => ( is => 'rw', isa => 'Time::Piece', ); has 'title' => ( is => 'rw', isa => 'Str', ); has 'location' => ( is => 'rw', isa => 'Str', ); has 'address' => ( is => 'rw', isa => 'Str', ); has 'document_url' => ( is => 'rw', isa => 'Str', ); has 'event_url' => ( is => 'rw', isa => 'Str', ); has 'event_id' => ( is => 'rw', isa => 'Str', ); has 'status' => ( is => 'rw', isa => 'Str', ); has 'post_id' => ( is => 'rw', isa => 'Int', );

$PM = "Perl Monk's";
$MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate";
$nysus = $PM . ' ' . $MCF;
Click here if you love Perl Monks

Replies are listed 'Best First'.
Re: Best way to compare two objects?
by Your Mother (Archbishop) on Mar 22, 2016 at 18:56 UTC

    Whereas I'd be stunned if there were anything like that out there because it's just not a trivial problem and has no single answer. Two objects representing database rows might have different instance ids but refer to the same row so they couldn't be deduplicated without inspecting meta information for the table and perhaps consulting the live data, for just one example. What constitutes a duplicate is part of the design of the object not just and not necessarily the data. Objects in Perl can be regular expressions, arrays, etc, too. Would one deduplicate /\w/ and /[^\W]/ or are they different? :P Deduplication may or may not need to consider metadata or the constraints of relationships to other data or objects or environment or temporal variables.

    Simple hash based objects without any "fancy" stuff might be trivial depending on the information design and it sounds like you're already on the right track for that.

      I've added an update to the parent post so you can see the attributes and their data types.

      $PM = "Perl Monk's";
      $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate";
      $nysus = $PM . ' ' . $MCF;
      Click here if you love Perl Monks

Re: Best way to compare two objects?
by stevieb (Canon) on Mar 22, 2016 at 19:16 UTC

    Have you tried the Data::Compare module? I use it frequently...

    use Data::Compare; print "same\n" if Compare $obj_1, $obj_2;

    If they aren't the same, Compare() large chunks of the module at a time, until you find out where they aren't the same, and it'll to lead you to other ways to test/bypass those sections.

Re: Best way to compare two objects?
by jeffa (Bishop) on Mar 22, 2016 at 19:16 UTC

    "I wish to compare two objects to determine if the attribute values are the same. "

    Do you want to compare two whole objects or just one attribute value held by two objects? If it is the former, then this begs the question: why? The latter, however, is fairly easy to solve:

    if ($object1->get_attr != $object2->get_attr) { print "they are different!" }
    Since you you know which attribute you are comparing, you will know what its type is and how to compare it accordingly.

    But back to the former case, comparing two whole objects. Rarely does one need to do this, which is probably why you found "very little guidance on this issue anywhere." It is not an issue for most of us. If you find yourself in a situation where you have to compare two whole objects then surely you can decompose the problem a little further. If you simply cannot, then most solutions for comparing whole objects involve writing a method that takes the object in question as an argument and inspects that object. This method (usually a class method) sees if it has every attribute required and if it can perform every method required. What is tricky is when the object in question has other attributes and methods. This is not a good road to take to find your solution. I recommend instead finding the 1 or 2 attributes or methods necessary to determine a delta. If you still insist on taking that road, look into overload the equality operator (=), which is a fairly natural thing to do in full featured OO languages, but not so much in Perl mostly because Perl has better ways to solve those problems. Good luck. :)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    

      It is the latter. I am pulling event information from a web page and then checking the event information periodically for updates. The event objects get stored in a file which then gets compared periodically with the latest information.

      $PM = "Perl Monk's";
      $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate";
      $nysus = $PM . ' ' . $MCF;
      Click here if you love Perl Monks

        How are you storing your objects in a file? Sounds like it might be better to store the data as JSON or in some other file-friendly format, read it back and compare Perl data structures. For that, there are plenty of tools.

        Also consider storing the response Last-Modified or Content-Length data and using a HEAD request on your check so you don't have to fetch the whole page each time to see if it's changed.


        The way forward always starts with a minimal test.
Re: Best way to compare two objects?
by GotToBTru (Prior) on Mar 22, 2016 at 18:48 UTC

    Compare two instances of the same object class? As I understand it, this is one of the historical uses for a toString method.

    But God demonstrates His own love toward us, in that while we were yet sinners, Christ died for us. Romans 5:8 (NASB)

Re: Best way to compare two objects?
by nysus (Parson) on Mar 22, 2016 at 21:11 UTC

    OK, here's what I came up with:

    package Event; use Moose; use Modern::Perl; my $meta = __PACKAGE__->meta; use overload 'eq' => \&compare; sub compare { no strict 'refs'; my ($event1, $event2) = @_; for my $attr( $meta->get_all_attributes ) { #skip attributes that shouldn't be compared next if $attr eq 'post_id' || $attr eq 'status'; my $type = $attr->type_constraint->name; my $attr_name = $attr->name; if ($type eq 'Str') { return 0 if $event1->$attr_name ne $event2->$attr_name; } if ($type eq 'Int') { return 0 if $event1->$attr_name != $event2->$attr_name; } if ($type eq 'Time::Piece') { no warnings 'uninitialized'; logd('comparing times'); return 0 if $event1->$attr_name != $event2->$attr_name; } } return 1; }

    Used like so:

    my $event1 = Event->new({location => 'hell'}); my $event2 = Event->new({location => 'hell'}); if ($event1 eq $event2) { say 'equal!'; } else { say 'not equal!'; }

    $PM = "Perl Monk's";
    $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate";
    $nysus = $PM . ' ' . $MCF;
    Click here if you love Perl Monks

      I haven't tested it, but I'd be surprised if no strict 'refs'; really was necessary, and if it was, I'd try to find a way to code it with all strictures enabled. In any case, if it really is necessary to disable strictures, it should be done in as small a scope as possible.