Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re^2: sub scope question

by papidave (Pilgrim)
on Feb 07, 2008 at 13:17 UTC ( [id://666788]=note: print w/replies, xml ) Need Help??


in reply to Re: sub scope question
in thread sub scope question

I have to admit, I was entirely perplexed as well by this until I realized that my in Perl acts like an actual executed statement, not merely a declaration (like it would be, for example, in C). As a result, you get a new instance of $list_ref every time the function is called -- which is why it doesn't stay shared.

When I want to create a shared variable with long-term state like that (i.e., a C-style "static"), I put the applicable function definitions in a scope block with the my statement at the outer level -- e.g.:

#!/usr/bin/perl -w use strict; my @firstlist = qw(1 2 3 4 5); my @secondlist = qw(A B C D E); process_list(\@firstlist); process_list(\@secondlist); { my $list_ref; sub process_list { ($list_ref) = @_; sub get_list { return @$list_ref; } print_list(); } } sub print_list { foreach my $item (get_list()) { print "LIST ITEM: $item\n"; } }

which produces:

LIST ITEM: 1 LIST ITEM: 2 LIST ITEM: 3 LIST ITEM: 4 LIST ITEM: 5 LIST ITEM: A LIST ITEM: B LIST ITEM: C LIST ITEM: D LIST ITEM: E

as expected. Naturally, you could (per ikegami, should) also move the get_list() subroutine outside the scope of process_list() for clarity, since it doesn't really add value there -- but I left it as-is to minimize changes from your original program.

Update: Strengthened some wording in response to comments from ikegami on Perl internals

Replies are listed 'Best First'.
Re^3: sub scope question
by ikegami (Patriarch) on Feb 07, 2008 at 13:38 UTC

    You say you get a new instance of $list_ref every time the function is called because my is not merely a declaration like in C. Yet you would get a new instance of local variables every time a function is called in C as well! Consider a re-entrant function, for example.

    In fact, as an optimization in Perl, you *don't* get a new instance of my variable every pass unless you do something that forces Perl to create a new variable. That's an implementation detail you shouldn't worry about, though.

    As for your suggestion to move my $list_ref, it seems to miss the point that nesting *named* functions has no benefit in Perl. Instead of trying to make the nested named function work, one should look at what one wants to achieve by nesting a named function and look for ways to meet that goal. (local *name = sub { ... }; is the likely answer.)

      ikegami,

      Thank you for the comments on my implementation details; I have improved my wording above. As regards the remainder of your response, I think we both agree that nesting named functions has no benefit in Perl; we differ only in how to resolve it.

      By going with an unnamed function assigned to a local var, you eliminate the "named" part; by moving $list_ref outside the function, you can then also move the named function to main scope, thereby eliminating the "nesting".

      In either case, I favor passing arguments into a subroutine over retention of state information in a closure or any kind of shared variable, because I find it easier to maintain -- but then, TMTOWTDI.

        Making a local variable variable into a semi-global one in order to use it to pass arguments to a function doesn't sound like the right approach to me. For starters, it breaks if the outer function is re-entrant and can break if the inner function is re-entrant, and that's when I normally use nested subs.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (3)
As of 2024-03-19 07:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found