Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

a sub within a sub -- revisiting

by punkish (Priest)
on Apr 10, 2010 at 03:59 UTC ( #833941=perlquestion: print w/ replies, xml ) Need Help??
punkish has asked for the wisdom of the Perl Monks concerning the following question:

I read Defining a sub within a sub: OK? with interest, but consider the following

sub foo { my @arra = ('a' .. 'z'); my @arrb; for ( 0 .. ( $#arra - 1) ) { bar($_); } bar($#arra); sub bar { my ($i) = @_; push @arrb, $arra[$i]; } return \@arrb; }

The above works, but what all sentiments and principles am I violating here? (besides, of course, Blond highlights with a hint of purple are just "so 2007

Essentially, bar() will never be called from outside foo(), and makes sense only within the context of foo(). In case I shouldn't be doing the above, then how should I rewrite it?

--

when small people start casting long shadows, it is time to go to bed

Comment on a sub within a sub -- revisiting
Download Code
Re: a sub within a sub -- revisiting
by Anonymous Monk on Apr 10, 2010 at 04:14 UTC
    bar is still visible outside of foo, so make it lexical
    sub foo { my $bar = sub { my ($i) = @_; push @arrb, $arra[$i]; }; $bar->($#arra); ... }

      Note that the above leaks if the anon sub accesses $bar. That would be the case if the anon sub is recursive, for example. I find the following simpler, and it doesn't leak.

      sub foo { ... local *bar = sub { ... }; bar(...); }
Re: a sub within a sub -- revisiting
by ikegami (Pope) on Apr 10, 2010 at 04:54 UTC

    The above works

    No, it doesn't. Call foo twice and check the results. (It always returns undef after the first call.)

      Just want to add one point to make this observation complete: this issue can be fixed by doing what the anonymous monk suggested above.

      However, the best is to code in a simple and straight forward manner. That's the principle.

      Peter (Guo) Pei

Re: a sub within a sub -- revisiting
by PeterPeiGuo (Hermit) on Apr 10, 2010 at 05:29 UTC

    Good code is usually straight forward, and this code is misleading in couple of ways:

    1. Visually, bar seems to be only available inside foo. But that's not true, bar can actually be called outside of foo.
    2. Make it even worse, when bar is called outside of foo, it does not do what's expected any more.

    Peter (Guo) Pei

      Actually, I disagree. The provided code is actually visually very helpful, as it leads (mind you, leads, not misleads) the reader to think that bar() makes sense in the context of foo().

      From OOP we know that Perl doesn't protect methods and variables. Perl would much rather that you didn't come into its home uninvited than put locks on its doors. The reader of the code should simply not call bar() from outside foo().

      That said, the suggestion to convert bar() into an anonymous sub is a good one. That makes things even clearer.

      --

      when small people start casting long shadows, it is time to go to bed
        The provided code is actually visually very helpful, as it leads (mind you, leads, not misleads) the reader to think that bar() makes sense in the context of foo().

        Maybe that code documents that its author intended such a thing, but to an experienced Perl programmer, I suspect that the code instead reads as if the author doesn't know how lexicals and sub declarations work in Perl.

        The ... code [of the OP] ... leads ... the reader to think that bar() makes sense in the context of foo().

        But does the code lead the reader to think that foo() does not make sense in the context of bar()? (See ikegami's Re: a sub within a sub -- revisiting.) If the code does not alert the reader to the subtle (side?) effect pointed out in that reply, it is not helpful and should either be heavily commented or another, more straightforward approach should be chosen to achieve the same effect. (Of course, this assumes the effect is intended in the first place!)

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (5)
As of 2014-11-28 01:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My preferred Perl binaries come from:














    Results (191 votes), past polls