perl5ever has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,

Is there a clever way to undef an "active" subroutine? I'd like to do this:

sub foo { undef &foo; ... }
I find it curious that undef-ing is not permitted but that this is allowed:
sub foo { *{foo} = sub { warn "second foo" }; ... }
In my case the sub I want to undef is an AUTOLOAD sub, and I'd want to remove it from the symbol table so it can't get called again.

Replies are listed 'Best First'.
Re: undef-ing an active subroutine
by ikegami (Patriarch) on Feb 01, 2010 at 15:20 UTC

    So deactivate it:

    >perl -wle"sub real_AUTOLOAD { undef &AUTOLOAD; } sub AUTOLOAD { print + 'A'; goto &real_AUTOLOAD } f() for 1..2;" A Undefined subroutine &main::f called at -e line 1.

    Getting rid of the whole glob works too:

    >perl -wle"sub AUTOLOAD { print 'A'; undef *AUTOLOAD; } f() for 1..2;" A Undefined subroutine &main::f called at -e line 1.
Re: undef-ing an active subroutine
by moritz (Cardinal) on Feb 01, 2010 at 15:29 UTC
    You can delete it from the symbol table:
    use strict; use warnings; sub foo { delete $::{foo}; print "alive\n"; } foo(); eval "foo()" or die $@;
    Note that I put the second call to foo into an eval because Perl looks up the symbol at compile type.
    Perl 6 - links to (nearly) everything that is Perl 6.
Re: undef-ing an active subroutine
by kennethk (Abbot) on Feb 01, 2010 at 15:36 UTC
    Along with the lovely suggestions from ikegami and moritz, you can use caller to make the deletion less fragile if you move your subroutine about:

    #!/usr/bin/perl use strict; use warnings; foo(); eval{foo()} or warn $@; print "Done\n"; sub foo { { no strict 'refs'; undef *{(caller(0))[3]}; } print "foo was called\n"; }
Re: undef-ing an active subroutine
by aquarium (Curate) on Feb 01, 2010 at 22:47 UTC
    unless there's a good reason it's probably safer coding to bind to new code that returns undef, instead of deleting a sub.
    the hardest line to type correctly is: stty erase ^H