Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Named Sort Subs with Strict?

by spudzeppelin (Pilgrim)
on Sep 19, 2000 at 21:26 UTC ( [id://33136]=perlquestion: print w/replies, xml ) Need Help??

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

I have a module (yes, mod_perl) I'm constructing where I have the obligatory use strict; at the beginning, but now it is causing me grief further down. Excerpts follow:

sub do_msalist { my (%country, %state, %msaname, @msakeys); ... foreach(sort by_americentric @msakeys) { ... } } #do_msalist sub by_americentric { $country{$b} cmp $country{$a} or $state{$a} cmp $state{$b} or $msaname{$a} cmp $msaname{$b} or $a <=> $b } #by_americentric

So now, the problem I'm encountering is that the use of strict is throwing a compile-time error with the package name of the hashes in the sort subroutine -- I've checked Camel2, Panther, and Hall, and none of them cover this particular dilemma in their treatment of sort.... What are your thoughts?

Spud Zeppelin * spud@spudzeppelin.com

Replies are listed 'Best First'.
Re: Named Sort Subs with Strict?
by Fastolfe (Vicar) on Sep 19, 2000 at 21:47 UTC
    Your hashes are scoped within the first function there, and are not accessible outside of it. Either move them so they are global (like with 'use vars'), or scope the sort function within the caller (or at least within the same block as the variables themselves).
    sub do_msalist { my (%country, %state, %msaname, @msakeys); sub by_americentric { $country{$b} cmp $country{$a} or $state{$a} cmp $state{$b} or $msaname{$a} cmp $msaname{$b} or $a <=> $b } foreach (sort by_americentric @msakeys) { ... } }
    When dealing with Perl scoping issues, try to think less about how Perl might "see" the variables and think about where the variables are physically placed in the source code.
Re: Named Sort Subs with Strict?
by stephen (Priest) on Sep 19, 2000 at 21:50 UTC
    The trouble is that you're localizing the variables in one block, then trying to use them in another. Since the variables exist in do_msalist(), they don't exist in by_americentric().

    You need to have the variables accessible by by_americentric(). There are a few ways to do this. One way is to put both of the subroutines inside an enclosing block, like this:

    { my (%country, %state, %msaname); sub do_msalist { my @msakeys = @_; foreach(sort by_americentric @msakeys) { #... } } sub by_americentric { $country{$b} cmp $country{$a} or $state{$a} cmp $state{$b} or $msaname{$a} cmp $msaname{$b} or $a <=> $b; } }

    Or, you can define the associative arrays as package variables with 'use vars'. Or you can just put by_americentric in as a blockin do_msalist, and call it that way:

    sub do_msalist { my @msakeys = @_; foreach(sort { $country{$b} cmp $country{$a} or $state{$a} cmp $state{$b} or $msaname{$a} cmp $msaname{$b} or $a <=> $b; } @msakeys) { #... } }
    That'll work if you only call by_americentric right there. But it's harder to read.

    stephen

Re: Named Sort Subs with Strict?
by chromatic (Archbishop) on Sep 19, 2000 at 21:45 UTC
    I wouldn't do it this way if I could help it, but:
    { my (%country, %state, %msaname, @msakeys); sub do_msalist { ... foreach(sort by_americentric @msakeys) { ... } } #do_msalist sub by_americentric { $country{$b} cmp $country{$a} or $state{$a} cmp $state{$b} or $msaname{$a} cmp $msaname{$b} or $a <=> $b } #by_americentric }
Re: Named Sort Subs with Strict?
by merlyn (Sage) on Sep 19, 2000 at 21:28 UTC
    The sort comparison function does in fact need access to the variables you are sorting! It's not psychic. {grin}

    Use an in-line sort block instead (like @output = sort { BLOCK } @input) and all will be well.

    -- Randal L. Schwartz, Perl hacker

Re: Named Sort Subs with Strict?
by runrig (Abbot) on Sep 20, 2000 at 00:39 UTC
    A 'Schwartzian Transform' is worth trying:
    sub do_msalist { my (%country, %state, %msaname, @msakeys); ... my @sorted = map { $$_[0] } sort { $$a[1] cmp $$b[1] } map { [$_, americentric_key( $country{$_}, $state{$_}, $msaname{$_}, $_ )]} @msakeys; for (@sorted) { ... } } sub americentric_key { # This part may need adjusting depending on your data sprintf("%10s%10s%10s%10d", @_; }
RE: Named Sort Subs with Strict?
by spudzeppelin (Pilgrim) on Sep 19, 2000 at 23:16 UTC

    I knew about sort {BLOCK} already -- but what I was hoping to achieve was something recyclable -- where if I add other do_blah subs besides do_msalist, they can call the same sort routine. Hence, I like Stephen's suggestion of giving the hashes package scope with use vars.

    This sort of triggers a new question -- I know package scope is a bad, bad thing under mod_perl in most cases, but can I work around it by explicitly undefing the hashes before the script returns?

    Spud Zeppelin * spud@spudzeppelin.com

      Perhaps someone else can answer more authoritatively, but my understanding of global variables is that
      • a) they're slower to access than local counterparts; and
      • b) in mod_perl they are persistent and take up space while your script isn't executing, and leave the environment "dirty" for the next time the CGI is called
      Emptying the hashes will fix problem (b) but they can't help you with (a). Unless you're doing a lot of data crunching, though, this might be an acceptable loss, though in my opinion it's still slightly poor coding practice, but you could do a lot worse.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://33136]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (4)
As of 2024-04-16 12:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found