6

Please take a look at the following code:

use strict;
use warnings;


print "subroutine is defined\n" if defined &myf;
myf();

sub myf
{
        print "called myf\n";
}

undef &myf;
#myf();
print "now subroutine is defined\n" if defined &myf;

The output is

subroutine is defined
called myf

The first print statement can print, does that mean the interpreter (or compiler?) looks further and sees the subroutine definition? If so, why it doesn't see the undef &myf; as the second print statement?

Thanks

password636
  • 981
  • 1
  • 7
  • 18
  • 4
    Because `undef` is code to run at runtime, but `sub` is a definition and happens at compile time. – Sobrique Sep 20 '16 at 10:57

1 Answers1

10

That doesn't have to do with scope, but with compile time and run time. Here's a simplified explanation.

The Perl interpreter will scan your code initially, and follow any use statements or BEGIN blocks. At that point, it sees all the subs, and notes them down in their respective packages. So now you have a &::myf in your symbol table.

When compile time has reached the end of the program, it will switch into run time.

At that point, it actually runs the code. Your first print statement is executed if &myf is defined. We know it is, because it got set at compile time. Perl then calls that function. All is well. Now you undef that entry in the symbol table. That occurs at run time, too.

After that, defined &myf returns false, so it doesn't print.

You even have the second call to myf() there in the code, but commented out. If you remove the comment, it will complain about Undefined subroutine &main::myf called. That's a good hint at what happened.

So in fact it doesn't look forward or backward in the code. It is already finished scanning the code at that time.


The different stages are explained in perlmod.

Note that there are not a lot of use cases for actually undefing a function. I don't see why you would remove it, unless you wanted to clean up your namespace manually.

simbabque
  • 53,749
  • 8
  • 73
  • 136
  • Great answer, but it doesn't explain why I can't write a statement `myf;` (or even `main::myf;`) before the subroutine is defined. – Borodin Sep 20 '16 at 12:40
  • 1
    @Borodin: because at compile time the compiller does not know that `myf` or `main::myf` barewords are subroutine (turn off `use strict` and you get: `Bareword "myf" not allowed while "strict subs" in use`. After subroutine is defined you have a `&::myf` in your symbol table and you can write barewords `myf` or `main::myf` after definition. To ensure perl that you want to call subroutine just put parentheses after bareword: `myf()` – Eugen Konkov Sep 20 '16 at 13:32
  • That was not part of the question @Borodin ;) – simbabque Sep 20 '16 at 13:59
  • @simbabque: No it wasn't. But on the surface it seems to contradict the idea that the compilation populates the symbol table so that the subroutine is available at run time. The ugly truth is that the compiler assumes that a simple `myf` is actually a string, despite `use strict 'subs'` being in place, and despite it producing a warning `Useless use of a constant ("myf") in void context` when treated as a string. All for the sake of backward-compatibility! – Borodin Sep 20 '16 at 14:33
  • @Borodin I read about this the other day. It might have been in another question. Was someone maybe discussing to remove this finally? – simbabque Sep 20 '16 at 14:44
  • @simbabque: Nothing I've heard of. I might poke around if I have time. – Borodin Sep 20 '16 at 15:36
  • It's not for backwards compatibility. Some people use paren-less calls to find typos and other errors at compile-time rather than when the call is executed. – ikegami Sep 20 '16 at 16:38