Set theory and objects

djberg96 on 2004-02-10T18:00:42

I received an interesting bug report for Set::Array from Marek Rouchal. The problem it seems, is that while the set methods work fine for plain data types, they don't work for sets of objects.

I am of two minds about this. On the one hand, he's right. I shouldn't return stringified results for objects/references. On the other hand, comparing object id's is almost never what you want anyway when comparing objects because it just isn't that useful.

In the vast majority of cases when you're going to be working with sets of objects, you should subclass and define your own methods to work specifically with those objects. For example, if I have $f1 = Foo->new(1,2) and $f2 = Foo->new(1,2), then for all intents and purposes $f1 and $f2 are identical.

Of course, the real reason I'm arguing is that I'm feeling lazy and I don't want to have to go back and fix my module. ;)


You don't know if they are identical

brian_d_foy on 2004-02-10T22:19:57

If you have
my $f1 = Foo->new( 1, 2 );
my $f2 = Foo->new( 1, 2 );
you cannot say whether or not they are identical, because you do not know what else the constructor might have done. For instance, it might have recorded a timestamp, connected to a different database, or something else that is not necessarily the same from call to call.

However, if you have
my $f1 = Foo->new( 1, 2 );
my $f2 = $f1;
then the object are the same because they are pointing at the same data. Indeed, their string values should be the same (although the class may have overloaded the stringify method to introduce some sort of randomness).

Comparing the stringified versions of objects can be useful. For instance, you can take a list of references and pull out the unique objects so you only call a method once on each object.

However, none of this probably means anything to your module :)

Re:You don't know if they are identical

djberg96 on 2004-02-11T03:32:30

Oh, I realize that $f1 and $f2 could be different. I was making the assumption (because I was too lazy to write out the code) that there wasn't anything tricky going on behind the scenes.

Actually, another thing you can do is use overload.pm and define your own "==" operator. Consider:

package Foo;
use strict;
use overload "==" => \=

sub new{
    my($class, $arg1, $arg2) = @_;
    bless{
        _arg1 => $arg1,
        _arg2 => $arg2,
    }, $class;
}

sub equals{
    my($obj1, $obj2) = @_;
    if( ($obj1->{_arg1} == $obj2->{_arg1})
        && ($obj1->{_arg2} == $obj2->{_arg2}) ){
            return 1;
    }
    else{
        return 0;
    }
}

package main;
use strict;

my $f1 = Foo->new(1,2);
my $f2 = Foo->new(1,2);
my $f3 = Foo->new(1,3);

if($f1 == $f2){
    print "Equal\n";
}
else{
    print "Not equal\n";
}

if($f1 == $f3){
    print "Equal\n";
}
else{
    print "Not equal\n";
}

Re:You don't know if they are identical

djberg96 on 2004-02-11T03:44:39

Whoops - didn't mean to hit submit yet. I was going to say that, even defining "==" doesn't help with my module and this is one case where Perl's OO begins to show its clunkiness, because now you have to deal with different types (strings and numbers vs references). I'm not saying it's impossible - I'm just saying it's extremely difficult, and you're better off subclassing.