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.

Pat
  • 36,282
  • 18
  • 72
  • 87
new_perl
  • 7,345
  • 11
  • 42
  • 72
  • 3
    Please choose a better subject line. – Raymond Chen Sep 23 '11 at 02:53
  • 1
    Nope the code you provided doesn't work in Perl 6. I ran it in the latest build of Rakudo and got this error: "Could not find sub &a". – GeneQ Sep 23 '11 at 03:00
  • 6
    No, it is not a bug (to the original headline) or a design flaw (to the revised headline). Some languages support nested function definitions, others don't. Perl 5 doesn't. Neither category is "flawed" because of it. – Dave Sherohman Sep 23 '11 at 12:53
  • 4
    Local functions are declared with local: `{ local *a = sub { print 1 }; a() } a()` – tchrist Sep 24 '11 at 02:31
  • 3
    Design flaw? No. Design choice? Yes. A design flaw is when a decision makes the general case more complex than it needs to be. A design choice is when a decision gives preference to one of several reasonable cases. Perl's decision to not permit nested functions facilitates closures without the need to take a sub reference; the general case makes simple things easy. Harder is the less general case of localizing function names. What it leaves untouched (no impact) is the ability to lexically scope code references (which is one alternative to nested subs). `local` is another alternative. – DavidO Oct 18 '11 at 22:55

7 Answers7

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.

Community
  • 1
  • 1
Joel Berger
  • 20,180
  • 5
  • 49
  • 104
  • FWIW, you can get the same package scoping for variables as well with `our` instead of `my`. – Thilo Sep 23 '11 at 03:14
  • @new_perl, Perl 6 is not a production language yet, therefore I haven't been following it yet. Why don't you download [Rakudo](http://rakudo.org/how-to-get-rakudo/) and find out. – Joel Berger Sep 23 '11 at 03:18
  • @Thilo, true. I was trying to demonstrate the failure that the OP was expecting. – Joel Berger Sep 23 '11 at 03:18
  • I'm not sure why you are trying to demonstrate using Deparse, but the argument is wrong since `perl -MO=Deparse -e"{ my $x; sub x { $x } }"` shows the sub in the curlies. – ikegami Sep 23 '11 at 03:34
  • @ikegami, ok well, then all the other stuff I said. – Joel Berger Sep 23 '11 at 03:44
  • @ikegami, after some consideration I will leave it in. The fact that the OP's code DID deparse like that is sufficient. Had it not, it would have precluded such an argument. – Joel Berger Sep 23 '11 at 04:36
  • 1
    @ikegami, one more thing. `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. – Joel Berger Sep 23 '11 at 04:50
  • 1
    Everything you say is true. (Well, except about the difficult part. It's clear that Deparse can very accurately tell the difference between a sub that captures and one that doesn't.) It's just your argument that's wrong. The output of Deparse does not show what you say it does. Deparse does not show in what order the code is compiled or executed. (It doesn't disprove it either. The conclusion just doesn't follow from the premises.) – ikegami Sep 23 '11 at 05:46
  • @ikegami, even if detecting a closure isn't difficult, presenting to the reader that the closure is closed over some variables is, therefore presenting it inside that scope accomplishes that. To the other point, again I say that since Deparse CAN show it outside the scope that subs are not subject to scope. E.g. the Deparse of `my $x = 5; {my $x = 3; print $x} print $x;` ne `my $x = 5; my $x = 3; print $x; print $x`, but if `{ sub x {print 1} } x` eq `sub x {print 1} x` then it shows that `sub` directives are not bound to scope. – Joel Berger Sep 23 '11 at 18:48
  • @Joel Berger, If you see a blue car, it doesn't mean cars are blue. – ikegami Sep 23 '11 at 20:01
  • 1
    Local functions are declared with local: `{ local *a = sub { print 1 }; a() } a()` – tchrist Sep 24 '11 at 02:31
  • @ikegami, I am attempting [proof by contradiction](http://en.wikipedia.org/wiki/Proof_by_contradiction). `Assert: all cars blue; see a red car; assertion is contradicted; qed cars may be other colors.` My argument goes like this `Assert: package sub declarations are block scoped; find any case where the parser ignores such scope; assertion is contradicted; qed package sub declarations are not block scoped.` – Joel Berger Sep 25 '11 at 16:52
  • @Joel Berger, I know, and you that argument is invalid. The conclusion that follows is "Not all sub declarations are block scoped". – ikegami Sep 25 '11 at 18:55
17

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:

  • nested named subs work as proper closures (see also: the "will not stay shared" warning in perl 5)
  • importing of subs from modules works into lexical scopes
  • built-in functions are provided in an outer lexical scope (the "setting") around the program, so overriding is as easy as declaring or importing a function of the same name
  • since lexpads are immutable at run time, the compiler can detect calls to unknown routines at compile time (niecza does that already, Rakudo only in the "optimizer" branch).
moritz
  • 12,710
  • 1
  • 41
  • 63
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;
Bill Ruppert
  • 8,956
  • 7
  • 27
  • 44
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 ...
Ven'Tatsu
  • 3,565
  • 16
  • 18
  • I’m glad *somebody* got it right. But you’re 21 votes behind. How lame is that? – tchrist Sep 24 '11 at 02:32
  • @tchrist, ok so there are dynamically scoped subroutines and lexically scoped anonymous subroutines. Is there a major reason why one is "right". Unless there is some reason to prefer the former, I prefer latter; it is very easy to pass these lexically scoped subs around by passing the variables that hold them. There can be closure generator functions which build my code for me. If I choose I can make them `local` (i.e. `local *name=$anon_sub`) which as far as I'm concerned just lets me call them without the dereference; who cares? – Joel Berger Sep 25 '11 at 14:49
  • 1
    readablilty argument: in Ven'Tatsu's example it takes some time to decipher when a certain subroutine exists and in which form. Lexically scoped variables holding anonymous subroutines are easy to see and follow where they came from. Finally there is the newbie argument. The OP asked a question that Perl programmers understand as a deeper thing than the OP expected. Why not show the method that is more DWIM to the newer Perl programmer, let him learn about local typeglobs later. I am not saying that mine is better, but at least equally valid, and I challenge being called wrong and lame. – Joel Berger Sep 25 '11 at 15:01
  • 1
    @JoelBerger Functions have names. Consider method calls. You have to use `local` to make that work. – tchrist Sep 25 '11 at 16:16
  • @tchrist, true, but that is getting rather far from the OP post. If the OP is trying to do OO, certainly (s)he will be aware of either `package` or Moosey ways of scoping methods. If the OP isn't aware of even these, (s)he probably ought not be pushing methods into some other package, but rather be subclassing. At least for now. – Joel Berger Sep 25 '11 at 16:22
  • 3
    @JoelBerger I explain it this way: **packages are for finding things, scopes are for hiding things.** Function *names* (and format names and filehande names, actually) in Perl are *always* bound to a package. Variables however may be bound to a package or to a scope. A name is a global idea; see also symbolic dereferencing. Once that model of what a name is for becomes clear, the confusion disappears. – tchrist Sep 25 '11 at 16:34
8

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:

  1. It might not be well implemented yet
  2. It might be removed without notice

So play with this new toy if you want, but you have been warned!

Joel Berger
  • 20,180
  • 5
  • 49
  • 104
  • What a horrible idea. Notice the lack of mention of 'local sub' or prototypes on these subs. – MkV Oct 13 '12 at 06:11
  • 2
    @downvoter, don't downvote me for not liking the idea, My answer is a true one. – Joel Berger Oct 13 '12 at 13:37
  • 1
    Update: Lexical subs did make it into 5.18 as an experimental feature: https://metacpan.org/module/RJBS/perl-5.18.0/pod/perlsub.pod#Lexical-Subroutines – plusplus May 29 '13 at 16:41
7

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 }
ikegami
  • 367,544
  • 15
  • 269
  • 518
6

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.

reinierpost
  • 8,425
  • 1
  • 38
  • 70