ff has asked for the wisdom of the Perl Monks concerning the following question:

I want to store a subroutine for sorting (a USERSUB) in one package and use it in another. My problem seems to be that the variables $a and $b are global to the package they are in and don't seem to be picked up across package boundaries. Here's what I wrote:

foreach ( sort gs::long_strings_first(), @$raw_hash_keys_ar ) { #do_stuff; } package gs; sub long_strings_first { return ( 0 ) unless defined $b; length $b <=> length $a || lc $b cmp lc $a }
but the variables were processed in alphabetical order, e.g.:

'All-American Residential Framing' 'Builders Assistant' 'Colson Plumbing' 'Electric Systems' 'Greenways' 'P & L Lighting' 'Regis Co.' 'Robert E. Matthews'
When I apply the logic directly (within braces following 'sort') I get the desired 'longest to shortest' sort of the terms.

foreach ( sort { length $b <=> length $a || lc $b cmp lc $a } @$raw_hash_keys_ar ) { # do stuff; } # Processed as: 'All-American Residential Framing' 'Robert E. Matthews' 'Builders Assistant' 'Electric Systems' 'Colson Plumbing' 'P & L Lighting' 'Regis Co.' 'Greenways'

Thanks.

Replies are listed 'Best First'.
Re: Accessing $a and $b of 'sort' across package boundaries
by ikegami (Patriarch) on Jun 06, 2005 at 19:20 UTC

    Use the alternate usage of sort:

    foreach ( sort gs::long_strings_first @$raw_hash_keys_ar ) { #do_stuff; } package gs; sub long_strings_first($$) { return 0 unless defined $_[0]; return 0 unless defined $_[1]; length $_[1] <=> length $_[0] || lc $_[1] cmp lc $_[0] }

    Why did you check if $b is undefined and not $a? If there can be undefined values in the list to be sorted, both $a and $b could be undefined. I added the extra check.

      Is that usage of sort any better/worse/different than something like this?
      foreach ( sort gs::long_strings_first($a,$b), @$raw_hash_keys_ar ) { #do_stuff; } package gs; sub long_strings_first { my ($first, $second) = @_; ... }

        Yes, I think there's a substantial difference in performance. Feel free to Benchmark.

        Also, doing my ($first, $second) = @_; instead of referencing $_[0] and $_[1] directly adds to the cost. It doesn't give anything in return either, since the names are no more descriptive than $_[0] and $_[1].

      Actually that return 0 unless defined bit was a ghastly way of checking whether there was even something to sort. Thanks for your interpretation and improvement of my lines. :-) (And thank you for the illustration of this other way of using sort that I didn't know/think about before. I've needed this for a while....)
Re: Accessing $a and $b of 'sort' across package boundaries
by salva (Canon) on Jun 06, 2005 at 19:42 UTC
    Sort::Key::Maker can simplify those multikey sortings a lot
    use Sort::Key::Maker sort_long_strings_first => sub { length $_, lc $_ }, qw(int -str); foreach (sort_long_strings_first @$raw_hash_keys_ar) { #do_stuff; }
Re: Accessing $a and $b of 'sort' across package boundaries
by ambrus (Abbot) on Jun 06, 2005 at 19:31 UTC

    Update: this answers the wrong question. I didn't read the question. Shame on me. Sorry.

    Go see what the pure-perl version of &List::Util::reduce does.

    It aliases the $a and $b in the scope of the caller to temporary scalars. I think that's faster then reading the original scalars. The best way would probably be if you make lexical aliases to those scalars, but that's out of question in a pure perl implementation which is used as a failback for the XS version.