18

I'm writing Perl for quite some time now and always discovering new things, and I just ran into something interesting that I don't have the explanation to it, nor found it over the web.

sub a {
   sub b {
     print "In B\n";
   }
}
b();

how come I can call b() from outside its scope and it works?

I know its a bad practice to do it, and I dont do it, I use closured and such for these cases, but just saw that.

snoofkin
  • 8,725
  • 14
  • 49
  • 86

4 Answers4

19

Subroutines are stored in a global namespace at compile time. In your example b(); is short hand for main::b();. To limit visibility of a function to a scope you need to assign an anonymous subroutines to a variable.

Both named and anonymous subroutines can form closures, but since named subroutines are only compiled once if you nest them they don't behave as many people expect.

use warnings;
sub one {
    my $var = shift;
    sub two {
        print "var: $var\n";
    }
}
one("test");
two();
one("fail");
two();
__END__
output:
Variable "$var" will not stay shared at -e line 5.
var: test
var: test

Nesting named subroutines is allowed in Perl but it's almost certainly a sign that the code is doing someting incorrectly.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Ven'Tatsu
  • 3,565
  • 16
  • 18
  • That is an interesting example. How do you explain that it does not update `$var` the second time? Curiously, if you remove the line `one("test")`, it complains about the undefined variable, but then `one("fail")` ***is*** allowed to update `$var`. Undefined behaviour? – TLP Apr 17 '12 at 13:56
  • I believe I found the answer in [perlref](http://perldoc.perl.org/perlref.html#Function-Templates). – TLP Apr 17 '12 at 14:04
  • 5
    @TLP, `sub two {}` is `BEGIN { *two = sub {} }`, so it captures over the `$var` that existed when it was compiled. `my` is basically a `new` that occurs on scope exit, so `two`'s `$var` becomes distinct from `one`'s `$var` after the first run of `$one`. – ikegami Apr 17 '12 at 16:03
  • So is this behavior of the sample code in this answer considered a feature, or just a byproduct of the nature of perl's symbol table? Because if I saw that code written down someplace, and I would have never guessed that it would behave that way. Just curious. – Erik Bennett Feb 28 '19 at 16:37
10

The "official" way to create nested subroutines in perl is to use the local keyword. For example:

sub a {
    local *b = sub {
        return 123;
    };
    return b();  # Works as expected
}

b();  # Error: "Undefined subroutine &main::b called at ..."

The perldoc page perlref has this example:

sub outer {
    my $x = $_[0] + 35;
    local *inner = sub { return $x * 19 };
    return $x + inner();
}

"This has the interesting effect of creating a function local to another function, something not normally supported in Perl."

Tero Niemi
  • 1,057
  • 11
  • 13
7

The following prints 123.

sub a {
    $b = 123;
}

a();
print $b, "\n";

So why are you surprised that the following does too?

sub a {
    sub b { return 123; }
}

a();
print b(), "\n";

Nowhere is any request for $b or &b to be lexical. In fact, you can't ask for &b to be lexical (yet).

sub b { ... }

is basically

BEGIN { *b = sub { ... }; }

where *b is the symbol table entry for $b, @b, ..., and of course &b. That means subs belong to packages, and thus can be called from anywhere within the package, or anywhere at all if their fully qualified name is used (MyPackage::b()).

ikegami
  • 367,544
  • 15
  • 269
  • 518
2

Subroutines are defined during compile time, and are not affected by scope. In other words, they cannot truly be nested. At least not as far as their own scope is concerned. After being defined, they are effectively removed from the source code.

TLP
  • 66,756
  • 10
  • 92
  • 149
  • 1
    Well, they can be nested, just not lexically scoped. – brian d foy Apr 17 '12 at 14:28
  • @briandfoy It seems there is more to it than I knew.. found a very cryptical explanation in [perlref](http://perldoc.perl.org/perlref.html#Function-Templates). Is this behaviour intentional? What possible use could it have? – TLP Apr 17 '12 at 14:32
  • @briandfoy - "I assume by 'can be nested' you mean 'can be physically placed inside another sub's code'; as opposed to 'can have semantics affected by such nested placement'", correct? – DVK Apr 17 '12 at 14:34
  • @DVK In Ven'Tatsu's answer, the two subs are seemingly nested, at least as far as the variable is concerned. I tried it with `strict`, and it is valid code. – TLP Apr 17 '12 at 14:36
  • @DVK Yes, "nested" as inside a "{ }" block in the source code. – dolmen Apr 18 '12 at 16:43
  • A long time ago I said subs couldn't be lexically scope. Now they can be, but it's an experimental feature: http://www.effectiveperlprogramming.com/2015/01/named-lexical-subroutines/ – brian d foy Jan 20 '15 at 07:33