Sort::Maker : anonymous sub is compiled outside of my module



I wanted to see how Sort::Maker could be used to sort the "meascodes" in this message:

http://groups.google.com/groups?selm=1165272390.675288.234670@xxxxxxxxxxxxxxxxxxxxxxxxxxx

To do this, I wrote this program:

132 use strict;
133 use warnings;
134 use Data::Dumper;
135 use Sort::Maker;
136
137 my $cost_order = 'A2yB';
138 my @sorted;
139
140 my $ms = [
141 '<table><tr><td meascode=\'y\'> </td></tr></table>',
142 '<table><tr><td meascode=\'B\'> </td></tr></table>',
143 '<table><tr><td meascode=\'2\'> </td></tr></table>',
144 '<table><tr><td meascode=\'A\'> </td></tr></table>'
145 ];
146
147 my $sorter = make_sorter(
148 plain => string => sub {
149 if (/meascode='(.)'/) {index($cost_order,$1)}
150 },
151 );
152 if ($@) { print "$@\n"; exit; }
153 @sorted = $sorter->(@$ms);
154 print Dumper(\@sorted);

However, this fails with "Global symbol "$cost_order" requires explicit package name at (eval 12) line 8."

I was a little surprised, since anonymous subs usually have access to lexical variables. I decided to make $cost_order a package variable (in main) and fully qualify it as $::cost_order in the anonymous sub, so I changed the lines of the program like so:

137 our $cost_order = 'A2yB';
149 if (/meascode='(.)'/) {index($::cost_order,$1)}

However, it fails again with the same error message as before. Thankfully, it prints out the key extraction code which shows that my colons have been removed from $::cost_order, and even when I use $main::cost_order, it gets changed to $cost_order--which causes the failure.

I then decided to change the variable $cost_order to a subroutine:

137 sub COST_ORDER { 'A2yB' }
149 if (/meascode='(.)'/) {index(COST_ORDER(),$1)}

And I get this error message: "Undefined subroutine &Sort::Maker::COST_ORDER called at (eval 12) line 8."

It looks like my anonymous sub is being compiled in Sort::Maker. No problem, I'll just put the qualifiers on the COST_ORDER():

149 if (/meascode='(.)'/) {index(::COST_ORDER(),$1)}

But it fails with the same error message. I can only assume that the colons were stripped from COST_ORDER() before the anonymous sub was compiled. Finally, I had an insight: Sort::Maker likes stuff to be in its package, so I try this:

137 sub COST_ORDER { 'A2yB' }
146 *{Sort::Maker::COST_ORDER} = \&COST_ORDER;
149 if (/meascode='(.)'/) {index(COST_ORDER(),$1)}

And it works.

Evidently, there is a bug/undocumented feature that causes an anonymous sub that the programmer writes in his package to be compiled in Sort::Maker, and Sort::Maker seems to make some modifications to the *text* of that subroutine before it's compiled :O

Perl 5.8.4
Sort::Maker 0.05
Debian 3.1 (i686)


--
paduille.4060.mumia.w@xxxxxxxxxxxxx
.



Relevant Pages

  • Re: Pattern matching for "best match"
    ... There is no anonymous sub in that code. ... And the test_for_match subroutine never exists since you are using block ... If your perl teacher suggested such code, ... lots of people do so instead of you doing so before posting it. ...
    (comp.lang.perl.misc)
  • Re: Pattern matching for "best match"
    ... > There is no anonymous sub in that code. ... > If your perl teacher suggested such code, ... >>and there are probably other optimization which can be done. ... > That style of code generating a subroutine isn't necessary since perl ...
    (comp.lang.perl.misc)