Alex Rivera | Logout

Is it a design flaw that Perl subs aren't lexically scoped?

Asked 2011-09-23T02:49:57.633
12
{
  sub a {
    print 1;
  }
}
a;

A bug,is it?

a should not be available from outside.

Does it work in Perl 6*?

* Sorry I don't have installed it yet.

Edit
Report

3 Answers

30

Are you asking why the sub is visible outside the block? If so then its because the compile time sub keyword puts the sub in the main namespace (unless you use the package keyword to create a new namespace). You can try something like

{
  my $a = sub {
    print 1;
  };
  $a->(); # works
}
$a->(); # fails

In this case the sub keyword is not creating a sub and putting it in the main namespace, but instead creating an anonymous subroutine and storing it in the lexically scoped variable. When the variable goes out of scope, it is no longer available (usually).

To read more check out perldoc perlsub

Also, did you know that you can inspect the way the Perl parser sees your code? Run perl with the flag -MO=Deparse as in perl -MO=Deparse yourscript.pl. Your original code parses as:

sub a {
    print 1;
}
{;};
a ;

The sub is compiled first, then a block is run with no code in it, then a is called.

For my example in Perl 6 see: Success, Failure. Note that in Perl 6, dereference is . not ->.

Edit: I have added another answer about new experimental support for lexical subroutines expected for Perl 5.18.

answered 2011-09-23T02:54:22.213
14

Subroutines are package scoped, not block scoped.

#!/usr/bin/perl
use strict;
use warnings;

package A;
sub a {
    print 1, "\n";
}
a();
1;

package B;
sub a {
    print 2, "\n";
}
a();
1;
answered 2011-09-23T03:02:10.597
13

Named subroutines in Perl are created as global names. Other answers have shown how to create a lexical subroutines by assigning an anonymous sub to a lexical variable. Another option is to use a local variable to create a dynamically scoped sub.

The primary differences between the two are call style and visibility. The dynamically scoped sub can be called like a named sub, and it will also be globally visible until the block it is defined in is left.

use strict;
use warnings;
sub test_sub {
    print "in test_sub\n";
    temp_sub();
}

{
    local *temp_sub = sub {
        print "in temp_sub\n";
    };
    temp_sub();
    test_sub();
}
test_sub();

This should print

in temp_sub
in test_sub
in temp_sub
in test_sub
Undefined subroutine &main::temp_sub called at ...
answered 2011-09-23T20:10:13.243

Your Answer