in reply to Using a sorting subroutine in a module with an array of arrays as parameters
A very similar problem is discussed in Inherit custom sort method from base class.
Basically, the problem is that $a and $b are package variables, and Perl special variables to boot (see perlvar).
When you run sort in the test.pl file, the $a and $b variables are being assigned values for use by the sort comparison subroutine. Assuming there is no package statement in test.pl, these special variables are in the main package, the default package in effect in the absence of any package statement; Perl is really assigning to the $main::a and $main::b (which can be abbreviated as $::a and $::b) special variables.
When you use $a and $b in a comparison subroutine defined in the personel package of file personel.pm, you're really accessing the $personel::a and $personel::b package variables. These variables have never been assigned any value. Update: This problem can be avoided by fully qualifying the package variable names as $main::a etc. as above, or by figuring out the package of the caller and constructing a symbolic reference as mentioned in the OP.
File personel.pm:
package personel; use warnings; use strict; sub sortAge { $b->[1] <=> $a->[1]; } sub cmpAge1 { $main::b->[1] <=> $main::a->[1]; } sub cmpAge2 { $::b ->[1] <=> $::a ->[1]; } sub cmpAge3 { # slower my $callingPkg = caller; no strict 'refs'; ${"$callingPkg\::b"}->[1] <=> ${"$callingPkg\::a"}->[1]; # ${"${callingPkg}::b"}->[1] <=> ${"${callingPkg}::a"}->[1]; # also + works } return 1;
File test.pl:
use warnings; use strict; use personel; use Data::Dump; my @personnel = ( [ 'amy', 35 ], [ 'bill', 55 ], [ 'george', 28 ], [ 'jason', 71 ], ); print "doesn't work: \n"; my @not_sorted_by_age = sort personel::sortAge @personnel; dd \@not_sorted_by_age; print "\n"; print "does work: \n"; my @sorted_by_age_descending1 = sort personel::cmpAge1 @personnel; dd \@sorted_by_age_descending1; print "\n"; print "also works: \n"; my @sorted_by_age_descending2 = sort personel::cmpAge2 @personnel; dd \@sorted_by_age_descending2; print "\n"; print "also works (somewhat slower): \n"; my @sorted_by_age_descending3 = sort personel::cmpAge3 @personnel; dd \@sorted_by_age_descending3; print "\n"; print "original array (should be unchanged): \n"; dd \@personnel; print "\n";
Output:
c:\@Work\Perl\monks\polmed>perl test.pl doesn't work: Use of uninitialized value in numeric comparison (<=>) at personel.pm +line 7. Use of uninitialized value in numeric comparison (<=>) at personel.pm +line 7. Use of uninitialized value in numeric comparison (<=>) at personel.pm +line 7. Use of uninitialized value in numeric comparison (<=>) at personel.pm +line 7. Use of uninitialized value in numeric comparison (<=>) at personel.pm +line 7. Use of uninitialized value in numeric comparison (<=>) at personel.pm +line 7. Use of uninitialized value in numeric comparison (<=>) at personel.pm +line 7. Use of uninitialized value in numeric comparison (<=>) at personel.pm +line 7. [["amy", 35], ["bill", 55], ["george", 28], ["jason", 71]] does work: [["jason", 71], ["bill", 55], ["amy", 35], ["george", 28]] also works: [["jason", 71], ["bill", 55], ["amy", 35], ["george", 28]] also works (somewhat slower): [["jason", 71], ["bill", 55], ["amy", 35], ["george", 28]] original array (should be unchanged): [["amy", 35], ["bill", 55], ["george", 28], ["jason", 71]]
(Note that had you been using warnings, Perl would have given you a valuable hint as to the underlying problem. Using strict is also a good idea for a novice — and for more venerable monks as well.)
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Using a sorting subroutine in a module with an array of arrays as parameters
by LanX (Saint) on Oct 19, 2013 at 20:25 UTC |