Using a sort routine from another package

I have a script and such a package:

# file: sortscript.pl use strict; use warnings; use SortPackage; my @arrays = ([1,"array1"],[10,"array3"],[4,"array2"]); print "Using sort outside package\n"; foreach (sort SortPackage::simplesort @arrays){ print $_->[1],"\n"; } print "\nUsing sort in same package\n"; SortPackage::sort_from_same_package(@arrays); 

-

 # file: SortPackage.pm use strict; use warnings; package SortPackage; sub simplesort{ return ($a->[0] <=> $b->[0]); } sub sort_from_same_package{ my @arrs = @_; foreach (sort simplesort @arrs){ print $_->[1],"\n"; } } 1; 

Running the script prints the result:

 $ perl sortscript.pl Using sort outside package Use of uninitialized value in numeric comparison (<=>) at SortPackage.pm line 15. Use of uninitialized value in numeric comparison (<=>) at SortPackage.pm line 15. Use of uninitialized value in numeric comparison (<=>) at SortPackage.pm line 15. Use of uninitialized value in numeric comparison (<=>) at SortPackage.pm line 15. Use of uninitialized value in numeric comparison (<=>) at SortPackage.pm line 15. Use of uninitialized value in numeric comparison (<=>) at SortPackage.pm line 15. array1 array3 array2 Using sort in same package array1 array2 array3 

Why can't I use the subroutine to sort correctly when it is in another package?

+7
source share
3 answers

As already mentioned, $a and $b are global packages, so another solution is to temporarily SortPackage on the call site in SortPackage packages:

 { local (*a, *b) = (*SortPackage::a, *SortPackage::b); foreach (sort SortPackage::simplesort @arrays){ print $_->[1],"\n"; } } 

But that, of course, is pretty ugly. I would just SortPackage export the full sorting procedure, not just the comparator:

 package SortPackage; use strict; sub _sort_by_first_element_comparator { return $a->[0] <=> $b->[0]; } sub sort_by_first_element { return sort _sort_by_first_element_comparator @_; } 
+6
source

$a and $b are special global package variables.

To use the main areas of $a and $b your comparator function will have to reference $::a or $main::a (as well as $b ).

However, this comparator function will not work when called from any other package, or even from its own package.

See the perlvars and perldoc for the sort function. The solution is also found in the last reference text:

If the prototype of the subroutine is "($$)" , the elements that should be compared by reference in @_ are like for a normal subroutine. This is slower than nonprotected routines, where the items to be compared are passed to the routines as global variables of the package $a and $b (see example below). Note that in the latter case, it is usually counterproductive to declare $a and $b as lexical.

+5
source

The special variables $a and $b are global packages. Your routine expects $SortPackage::a and $SortPackage::b . When you call it from sortscript.pl , the variables $main::a and $main::b are set by sort .

The solution is to use a prototyped subroutine:

 package SortPackage; sub simplesort ($$) { return ($_[0]->[0] <=> $_[1]->[0]); } 

This is a bit slower (since you have the actual parameters that are passed, instead of reading the predefined global ones), but it allows you to use routines from other packages by name as you try.

+5
source

All Articles