Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl sort won't use function from another package

Tags:

perl

I have a function for case insensitive sorting. It works if it's from the same package, but not otherwise.

This works:

my @arr = sort {lc $a cmp lc $b} @list;

This works (if a function called "isort" is defined in the same file):

my @arr = sort isort @list;

This does not (function exported with Exporter from another package):

my @arr = sort isort @list;

This does not (function referred to explicitly by package name):

my @arr = sort Utils::isort @list;

What is going on? How do I put a sorting function in another package?

like image 831
felwithe Avatar asked Dec 09 '19 13:12

felwithe


1 Answers

What evidence do you have for it not working? Have you put a print() statement in the subroutine to see if it's being called?

I suspect you're being tripped up by this (from perldoc -f sort):

$a and $b are set as package globals in the package the sort() is called from. That means $main::a and $main::b (or $::a and $::b ) in the main package, $FooPack::a and $FooPack::b in the FooPack package, etc.

Oh, and later on it's more specific:

Sort subroutines written using $a and $b are bound to their calling package. It is possible, but of limited interest, to define them in a different package, since the subroutine must still refer to the calling package's $a and $b:

package Foo;
sub lexi { $Bar::a cmp $Bar::b }
package Bar;
... sort Foo::lexi ...

Use the prototyped versions (see above) for a more generic alternative.

The "prototyped versions" are described above like this:

If the subroutine's prototype is ($$) , the elements to be compared are passed by reference in @_, as for a normal subroutine. This is slower than unprototyped subroutines, where the elements to be compared are passed into the subroutine as the package global variables $a and $b (see example below).

So you could try rewriting your subroutine like this:

package Utils;

sub isort ($$) {
  my ($a, $b) = @_;

  # existing code...
}

And then calling it using one of your last two alternatives.

like image 70
Dave Cross Avatar answered Sep 20 '22 19:09

Dave Cross