{ 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.
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.
our instead of my.perl -MO=Deparse -e '{ sub x { $x } my $x}' deparses as the OP's, therefore I submit that it is presented as is, in case the sub declaration forms a closure. I imagine that checking for the presence of a closure is difficult, therefore B::Deparse takes the easy road: if a lexical variable is declared before a subroutine in the same scope, it shows the subroutine declaration in that scope.{ local *a = sub { print 1 }; a() } a()In Perl 6, subs are indeed lexically scoped, which is why the code throws an error (as several people have pointed out already).
This has several interesting implications:
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 ... local (i.e. local *name=$anon_sub) which as far as I'm concerned just lets me call them without the dereference; who cares?local to make that work.At the risk of another scolding by @tchrist, I am adding another answer for completeness. The as yet to be released Perl 5.18 is expected to include lexical subroutines as an experimental feature.
Here is a link to the relevant documentation. Again, this is very experimental, it should not be used for production code for two reasons:
So play with this new toy if you want, but you have been warned!
If you see the code compile, run and print "1", then you are not experiencing a bug.
You seem to be expecting subroutines to only be callable inside the lexical scope in which they are defined. That would be bad, because that would mean that one wouldn't be able to call subroutines defined in other files. Maybe you didn't realise that each file is evaluated in its own lexical scope? That allows the likes of
my $x = ...; sub f { $x } Yes, I think it is a design flaw - more specifically, the initial choice of using dynamic scoping rather than lexical scoping made in Perl, which naturally leads to this behavior. But not all language designers and users would agree. So the question you ask doesn't have a clear answer.
Lexical scoping was added in Perl 5, but as an optional feature, you always need to indicate it specifically. With that design choice I fully agree: backward compatibility is important.
{ local *a = sub { print 1 }; a() } a()localis another alternative.