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

Stumbled upon the ability to define subroutines within subroutines. Don't know if this is intentional or not on Mr Wall's part, but I was trying to think of ways to take advantage of it nonetheless. Alas, my novice Perl imagination has yet to be expanded. Perhaps a wiser Monk can show me new pathways...

Example:

sub foo { print "Hello\n"; sub bar { print "world!\n"; } bar(); } foo(); bar();
...Yields:
Hello
world!
world!

Try it yourself!

Replies are listed 'Best First'.
(ichimunki) Re: Sub Definitions Within Subs: Best Way to Exploit
by ichimunki (Priest) on Oct 11, 2001 at 01:58 UTC
    The fact that your sample text shows "world!" twice proves that bar() is not truly "inside" foo(). The normal scope rules do not come into play.

    If you truly want to keep a lexical sub, you should build it into a coderef:
    sub foo { my $bar = sub { print "world!\n" }; print "Hello\n"; &$bar; #also can be written as: $bar->(); } foo(); #&$bar here will not work since $bar is only valid inside foo.
    update: Please note that there are some great examples of using nested subs to create closures, especially a great example on using this technique to create a static variable. This can be very useful if a certain sub should set a global value once and only once, so it computes the value and then creates an accessor routine that refers to the variable.

    Although stylistically I think you'd only want to do this if you were going to create a bunch of them (as in tilly's masterful Why I Like Functional Programming). Having a bunch of closures running around could make it hard to remember what's where and why. :)
(Ovid) Re: Sub Definitions Within Subs: Best Way to Exploit
by Ovid (Cardinal) on Oct 11, 2001 at 02:52 UTC

    Unfortunately, any subroutine that you define like that will be put into the namespace of the package that it's resident in. Thus, you cannot have lexically scoped subroutines. From what I understand, we will have lexically scoped subs in Perl6.

    What you want is a closure:

    my $bar = sub { print shift }; sub foo { print "Hello\n"; $bar->( "Saluton mondo!\n" ); } foo(); $bar->( "Hello world!\n" );

    Hmm... as I recall, the proper definition of a closure is an anonymous code reference that contains a reference to a lexically scoped variable that is defined outside of itself. Since this example doesn't really do that, is it, strictly speaking, a closure?

    Cheers,
    Ovid

    Vote for paco!

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      Actually, it doesn't need to be anonymous or a code ref to be a closure; it just has to refer to lexical variables defined outside of its scope. This is a closure:
      my $foo; sub bar { print $foo; }
      Any further changes to the value of $foo in the future will not change the private value that bar() now has.
        It does need to be inside another sub. The code has to be something like:
        sub baz { my $foo=shift; sub bar { print $foo; } } baz("abc"); bar; baz("123"); bar;
        which will print abcabc. The change to the $foo variable in the second call does not affect subroutine bar. It has a 'closed', localised and personal $foo variable, that cannot be changed by outside influences - only by bar itself. Thus the name 'closure'.
Re: Sub Definitions Within Subs: Best Way to Exploit
by pjf (Curate) on Oct 11, 2001 at 03:56 UTC
    G'day crazysniffable,

    Being able to define subroutines within subroutines is intentional. The main uses for this sort of thing is within AUTOLOAD methods, which allows subroutines to be generated "on demand". Usually a little bit of eval magic occurs here as well, to make sure an appropriately named sub is generated.

    As pointed out above, a subroutine attaches itself to its current package, regardless of where you define it. This is exactly what you want for AUTOLOAD methods.

    The perlbot man page has an example of using AUTOLOAD down the bottom. You might want to check it out if you're curious.

    Cheers,
    Paul

Re: Sub Definitions Within Subs: Best Way to Exploit
by Tetramin (Sexton) on Oct 11, 2001 at 13:44 UTC
    One use I can think of are static variables
    sub outside_foo { my $STATIC; my $done = 1; sub foo{ $done or outside_foo(); print "\nSTATIC is ", ++$STATIC; } } foo(); foo(); foo();
Re: Sub Definitions Within Subs: Best Way to Exploit
by crazysniffable (Acolyte) on Oct 11, 2001 at 01:13 UTC
    Granted, I know this isn't pretty or even Good Programming Practice; but it's just a puzzle I found amusing.

    "Dogs luv me cuz I'm crazy sniffable / I bet you never knew I got ill peripherals"