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

Hi Monks, I need some help with OO Perl.
Here by_id function in SORT is not working since object type (for $a and $b) is not defined in the first place.
Can I define them ??
In Module SORT.pm the Function by_id has no idea what's 'id' function we are talking about
My assumption is that SORT.pm need to know at compile time that what is 'id' function and where it's coming from when applied to 'sorting variables' $a and $b
package main; use X; use SORT; my $p = new X(10); my$q = new X(20); my $r = new X(15); foreach my $obj (sort by_id ($p,$q,$r)){ print $obj->id; } package X; require Exporter; @ISA = qw(Exporter); @EXPORT = qw(id); sub new { my $class =shift; my $self = { _id => shift }; bless $self, $class; } sub id { my $self = shift; return $self->{_id}; } 1; package SORT; use X; require Exporter; @ISA = qw(Exporter); @EXPORT = qw(by_id); sub by_id { $a->id <=> $b->id; } 1;
Above Code when run gives the error
Can't call method "id" without a package or object reference at SORT.pm

How do I make it working???
Thanks,
Artist

Replies are listed 'Best First'.
Re (tilly) 1: OO and sorting
by tilly (Archbishop) on Jul 26, 2001 at 01:25 UTC
    The thread $a and strict has discussion of your problem, and Re (tilly) 5: $a and strict has a solution to your problem.

    However if your code is not performance critical and you want to have a solution that is more in line with working with objects, you may prefer to create the following base class:

    package Sortable; use overload 'cmp' => \&_cmp; sub _cmp { $_[0]->cmp($_[1]); } 1;
    Now just inherit from that and define a useful 'cmp' method and you can sort in whatever order makes sense. For instance:
    package AnonArray; # Quick demo of how Sortable works use Sortable; @ISA = ('Sortable'); sub cmp { my $self = shift; my $other = shift; my $len = @$self > @$other ? @$self : @$other; for (0..($len - 1)) { if (my $res = $self->[$_] cmp $other->[$_]) { return $res; } } if ($len < @$self) { return 1; } elsif ($len < @$other) { return -1; } else { return 0; } } sub new { my $class = shift; return bless [@_], $class; } 1;
    allows you to make anonymous arrays that will compare with other anonymous arrays in a lexicographical sort.

    UPDATE
    For the record I don't have an opinion on whether the overload approach is a good idea. It was something I was playing with, and it was satisfying to see that I could set up complex sorts using that idea. But I just don't know if it is really worth it to design a system that much at variance with how Perl works by default. If anyone has a more concrete opinion, I would be interested to hear it...

    UPDATE 2
    Sorry, I should have given an example of what it looks like in action. Well suppose that you create an array of AnonArrays and put it in @to_sort. Then you just try:

    @sorted = sort @to_sort;
    and the comparison function is picked up behind the scenes from Sortable. :-)
Re: OO and sorting
by bikeNomad (Priest) on Jul 26, 2001 at 00:58 UTC
    Why not just call sort() from package SORT?

    package SORT; use X; require Exporter; @ISA = qw(Exporter); @EXPORT = qw(sorted); sub by_id { $a->id <=> $b->id; } sub sorted { sort by_id @_ } 1;
      Hi
      Thanks guys,
      Both approaches are working fine. I like BikeNomad's approach better as it looks simple and has potential to introduce more OO.
      Artist.
Re: OO and sorting
by dragonchild (Archbishop) on Jul 26, 2001 at 00:38 UTC
    $a and $b are special globals. When you defined by_id() in package SORT, you've actually defined { $SORT::a->id <=> $SORT::b->id }. What you'll need to do is pass the package name in (somehow) and put it into your function definition.
Re: OO and sorting
by japhy (Canon) on Jul 26, 2001 at 01:55 UTC
    If you create a sorting function, and give it a prototype of ($$), it takes its two arguments and puts them in the @_ array:
    package other; sub backwards ($$) { $_[1] cmp $_[0] } # from perlfunc

    _____________________________________________________
    Jeff japhy Pinyan: Perl, regex, and perl hacker.
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: OO and sorting
by suaveant (Parson) on Jul 26, 2001 at 00:40 UTC
    dragonchild is right, you can do $main::a and $main::b, but that is not very portable...

    Update I didn't mean portable, I meant re-usable...

    here is code that works....

    sub by_id { my $pkg = (caller())[0]; ${"${pkg}::a"}->id <=> ${"${pkg}::b"}->id; }
    dunno how good a way to do it that is... but it should work...

                    - Ant