I have a script and a package like so:
# 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 produces the output:
$ 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 am I not able to correctly use the subroutine to sort with when it is in another package?
As has been mentioned, $a
and $b
are package globals, so another solution is to temporarily alias the globals at the call site to the ones in package SortPackage
:
{
local (*a, *b) = (*SortPackage::a, *SortPackage::b);
foreach (sort SortPackage::simplesort @arrays){
print $_->[1],"\n";
}
}
But this is pretty ugly, of course. I would just have SortPackage
export a complete sorting routine, not just a 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 @_;
}
The special variables $a
and $b
are package globals. Your subroutine expects $SortPackage::a
and $SortPackage::b
. When you call it from sortscript.pl
, the variables $main::a
and $main::b
are being set by sort
.
The solution is to use a prototyped subroutine:
package SortPackage;
sub simplesort ($$) {
return ($_[0]->[0] <=> $_[1]->[0]);
}
It's a little slower (since you have actual parameters being passed, instead of reading pre-set globals), but it allows you to use subroutines from other packages by name, as you are attempting.
$a
and $b
are special "package global" variables.
To use the main scope's $a
and $b
your comparator function would have to refer to $::a
or $main::a
(and likewise for $b
).
However that comparator function then wouldn't work when called from any other package, or even from within its own package.
See the perlvars
help and the perldoc
for the sort
function. The solution is also in the latter help text:
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). Note that in the latter case, it is usually counter‐productive to declare$a
and$b
as lexicals.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With